CH#56C 异象石

一道贼可怕的题目,这能想到就想到,不能想到就等着被算法题目(日常)揍吧。
另外这道题有参考别人代码之嫌,实属弟弟行为,下次一定不。
题目链接:良心网站acwing
题意:中文题啊=_=
思路:LCA+set维护,首先你得要理解时间戳的概念,对于出现的异象石你可以发现一个规律叫做按照时间戳排序,异象石的节点连成一个圈,并且累加相邻的节点,最后得到的结果恰好是路径和的两倍,这是本题最为可怕的地方,因为你根本想不到竟然还可以这样累加,我下次该怎么想这种题目?手画样例?还是默默的把这种结论记下来?很难考到这么奇怪的题目吧,叹息。另外本题有个地方你记下时间戳以后,对应的pos位置也要记录下来。这就完成了。

#define _CRT_SECURE_NO_WARNINGS 1
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#define ls rt<<1
#define rs rt<<1|1
#define pb push_back
#define fi first
#define se second
#define yes puts("YES")
#define no puts("NO")
#define ios ios::sync_with_stdio(0);
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define aint(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long LL;
typedef set<int>::iterator IT;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int N = 1e5+9 ,M = 1e6+1;
const int Maxn=1000010;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
LL qp(LL x,LL y){LL ans=1;x%=mod;while(y){if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;}
LL inv(LL x){return qp(x,mod-2);}
///head
int n ,m ;
int head[N], edge[N<<1], Next[N<<1], ver[N<<1], tot;
int pos[N], dfn[N] ,vis[N];
int dep[N], fa[N][20];
LL dis[N][20] ,ans;
set<int>s;
void add(int x, int y , int z){
    ver[++tot] = y , edge[tot] = z , Next[tot] = head[x] , head[x] = tot;
}
int cnt ;
void bfs(){
    queue<int>q;
    q.push(1); vis[1] = 1; dep[1] = 1;
    while(q.size()){
        int x = q.front();q.pop();
        for(int i = head[x]; i ; i = Next[i]){
            int y = ver[i];
            if(vis[y])continue;
            vis[y] = 1;
            dep[y] = dep[x] + 1;
            fa[y][0] = x;
            dis[y][0] = edge[i];
            for(int j = 1 ; j < 20 ;j ++){
                fa[y][j] = fa[fa[y][j-1]][j-1];
                dis[y][j] = dis[fa[y][j-1]][j-1] + dis[y][j-1];
            }
            q.push(y);
        }
    }
}

LL lca(int x,int y){
    LL res = 0;
    if(dep[x] > dep[y])swap(x , y);
    for(int i = 19; i >= 0; i --)
        if(dep[fa[y][i]] >= dep[x])res += dis[y][i],y = fa[y][i];
    if(x == y) return res;
    for(int i = 19 ; i >= 0; i --)
    if(fa[x][i] != fa[y][i])
        res += dis[x][i] + dis[y][i] , x = fa[x][i], y = fa[y][i];
    return res + dis[x][0] + dis[y][0];
}

void dfs(int x,int fa = -1){
    dfn[x] = ++cnt, pos[cnt] = x;
    for(int i = head[x]; i ; i = Next[i]){
        int y = ver[i];
        if(y == fa) continue;
        dfs(y ,x);
    }
}
IT L(IT it)
{
	if(it==s.begin())return --s.end();
	return --it;
}
IT R(IT it)
{
	if(it==--s.end())return s.begin();
	return ++it;
}

int main(){
    while(~scanf("%d", &n )){
        memset(head, 0 , sizeof head);
        s.clear(); ans = 0;
        for(int i = 1; i < n ; i ++){
            int x, y , z;
            scanf("%d %d %d" ,&x, &y , &z);
            add(x,y,z);
            add(y,x,z);
        }
        dfs(1);
        bfs();
        scanf("%d" , &m);
        while(m --){
            char op[4] ;
            int ope ;
            scanf("%s",op);
            if(op[0] == '+'){
                scanf("%d" , &ope);
                if(SZ(s)){
                    auto it1 = s.lower_bound(dfn[ope]);
                    if(it1 == s.end()) it1 = s.begin();
                    auto it2 = L(it1);
                    ans += lca(ope, pos[*it2]) + lca(ope,pos[*it1]) - lca(pos[*it1],pos[*it2]);
                }
                s.insert(dfn[ope]);
            }
            else if(op[0] == '-'){
                scanf("%d" , &ope);
                auto it1 = s.find(dfn[ope]);
                auto it2 = L(it1);
                it1 = R(it1);
                ans -= lca(ope , pos[*it2]) + lca(ope, pos[*it1]) - lca(pos[*it2] , pos[*it1]);
                s.erase(dfn[ope]);
            }
            else{
                printf("%lld\n",ans / 2);
            }
        }
    }
}
全部评论

相关推荐

求实习的小白1213:华科去这 你是真敢去啊
点赞 评论 收藏
分享
真烦好烦真烦:牛友太有实力了
点赞 评论 收藏
分享
关于我大学本科四年,想了很多,但还是不知道该怎么动笔&nbsp;“大学四年,是我从懵懂少年走向职场青年的转折期。这一路跌跌撞撞,有迷茫,有遗憾,也有成长和决心。”&nbsp;大一刚进来时仍然有高中那股学习劲,经常一个人去图书馆学高等数学,但后面劲头一过便开始在宿舍开启躺平生活(现在想想那段时间真的很爽,无忧无虑)。由于大一担任班干部,所以经常要跟其他班的班干部交流,在此期间认识了隔壁班的一位女生,短发而很可爱,因为很多团建还有比赛都是我们两班一起参加的,而且我和她都是负责人,所以交集很多,后面慢慢地彼此对产生了好感,所以在大一刚开学的2个月后,我们在一起了,彼此之前都是初恋。但当时我真的是太太太直男了,对感情的想...
真烦好烦真烦:骗哥们可以,别把你自己也骗到了就行。哥们被你骗了真无所谓的,打个哈哈就过了。但希望你打完这段话后擦一下眼角,别让眼泪掉在手机屏幕上了就行。你说的这些话,哥们信一下也是没什么的。还能让你有个心里安慰,但这种话说出来骗骗兄弟就差不多得了,哥们信你一下也不会少块肉,但是你别搞得自己也当真了就行。哥们被你骗一下是真无所谓的,兄弟笑笑也就过去了。真不是哥们想要破你防,你擦擦眼泪好好想想,除了兄弟谁还会信你这些话?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务