题面:从前有一个国家,国家里面的城市是树形结构的。这个国家的国王是个萝莉控,爱上了一个小恶魔。
小恶魔喜欢制造混乱,经常让国王修改城市之间的道路系统。每条道路有两种颜色,黑与白。
修改有两种,一是把城市a和b之间的道路全部翻转颜色,二是把城市a和b之间道路的相邻路翻色。
国王的萝莉女儿,WJMZBMR很关心国家道路状况,她会询问a和b之间的道路有多少是黑色的。
一开始所有道路都是白色。
分析:
第一种操作就是最简单的树链剖分。
第二种操作如果要用树链剖分,需要仔细思考。
首先,还是只能更新那logN条链,可以想到在链上打标记来表示更新了周围的点。这样做是否可行呢?
在路径的重链上,中间的点是不变的,被标记了两次,这是合法的。
考虑询问。在询问的时候,存在两个问题,1.重链的点很多,2.某个点的度数很多。这将导致复杂度变成O(n)。
需要修改标记的含义,对于2,一条边只需要一个标记的点就够了,最适合的点是这条边的父结点。
对于1,重链上中间的点是不必标记的。
综上,在一个父节点打标记表示修改了它的孩子轻边。剩下O(logN)个端点特殊处理一下,复杂不会退化。
标记区间更新点,翻转区间更新边,这个操作可以用线段树完成。(边的id用它的子结点编号,这个写着的时候挺容易出错的。
复杂度O(Qlognlogn)
/********************************************************* * ------------------ * * author AbyssFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> #include<climits> using namespace std; const int maxn = 1e5+5; int hd[maxn], nx[maxn<<1], to[maxn<<1], ec; void add_edge(int u,int v) { nx[ec] = hd[u]; to[ec] = v; hd[u] = ec++; } void init_g(int n){ memset(hd+1,0xff,n*sizeof(int)); ec = 0; } #define eachedge int i = hd[u]; ~i; i = nx[i] #define ifvalid int v = to[i]; if(v == fa[u]) continue; int n; /*----------------------------------------*/ int fa[maxn]; int tr_sz[maxn]; int top[maxn]; int son[maxn]; int dep[maxn]; int id[maxn]; int id_cnt; // id[0] = tr_sz[0] = 0 void dfs(int u,int f = 0,int d = 0) { dep[u] = d; son[u] = 0; fa[u] = f; tr_sz[u] = 1; for(eachedge){ ifvalid dfs(v,u,d+1); tr_sz[u] += tr_sz[v]; if(tr_sz[v] > tr_sz[son[u]]){ son[u] = v; } } } void sub_dv(int u,int tp) { top[u] = tp; id[u] = ++id_cnt; if(son[u]) sub_dv(son[u],tp); for(eachedge){ ifvalid if(v != son[u]) sub_dv(v,v); } } /*----------------------------------------*/ #define para int o = 1,int l = 1,int r = n #define lo (o<<1) #define ro (o<<1|1) #define Tvar int md = (l+r)>>1; #define lsn lo,l,md #define rsn ro,md+1,r #define insd ql<=l&&r<=qr #define qpara int ql,int qr,para #define qlsn ql, qr,lsn #define qrsn ql, qr,rsn const int ST_SIZE = 1<<18; int flp[ST_SIZE], sum[ST_SIZE]; //edge int flg[ST_SIZE];//vertex void build(para) { sum[o] = flp[o] = flg[o] = 0; if(l < r){ Tvar build(lsn); build(rsn); } } inline void sink(int o,int tot) { flp[o] ^= 1; sum[o] = tot - sum[o]; } inline void dwn_flp(int o,int l,int r) { if(flp[o]){ Tvar sink(lo,md+1-l); sink(ro,r-md); flp[o] = 0; } } void update_flp(qpara) { if(insd){ sink(o,r+1-l); } else { Tvar dwn_flp(o,l,r); if(ql <= md) update_flp(qlsn); if(qr > md) update_flp(qrsn); sum[o] = sum[lo] + sum[ro]; } } int q_flp_sum(qpara) { if(insd) return sum[o]; else { Tvar dwn_flp(o,l,r); int re = 0; if(ql <= md) re += q_flp_sum(qlsn); if(qr > md) re += q_flp_sum(qrsn); return re; } } /*----------------------------------------*/ int q_flg(int qpos, para) { if(l == r) return flg[o]; else { Tvar return flg[o]^(qpos <= md ? q_flg(qpos,lsn) : q_flg(qpos,rsn)); } } void update_flg(qpara) { if(insd) flg[o] ^= 1; else { Tvar if(ql <= md) update_flg(qlsn); if(qr > md) update_flg(qrsn); } } /*----------------------------------------*/ void rvPath(int a,int b) { int p = top[a], q = top[b]; while(p != q){ if(dep[p] < dep[q]) swap(a,b), swap(p,q); update_flp(id[p],id[a]); p = top[a = fa[p]]; } if(a != b){ if(dep[a] > dep[b]) swap(a,b); update_flp(id[son[a]],id[b]); } } void rvAdj(int a,int b) { int p = top[a], q = top[b]; while(p != q){ if(dep[p] < dep[q]) swap(a,b), swap(p,q); update_flg(id[p],id[a]); update_flp(id[p],id[p]); if(son[a]) { update_flp(id[son[a]],id[son[a]]); } p = top[a = fa[p]]; } if(dep[a] > dep[b]) swap(a,b); update_flg(id[a],id[b]); update_flp(id[a],id[a]); if(son[b]) { update_flp(id[son[b]],id[son[b]]); } } int query(int a,int b) { int re = 0; int p = top[a], q = top[b]; while(p != q){ if(dep[p] < dep[q]) swap(a,b), swap(p,q); if(a != p){ re += q_flp_sum(id[son[p]],id[a]); } re += q_flg(id[fa[p]]) ^ q_flp_sum(id[p],id[p]); p = top[a = fa[p]]; } if(a != b){ if(dep[a] > dep[b]) swap(a,b); re += q_flp_sum(id[son[a]],id[b]); } return re; } /*----------------------------------------*/ void init() { scanf("%d",&n); init_g(n); int a,b; for(int i = 1; i < n; i++){ scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); } } void solve() { id_cnt = 0; dfs(1); sub_dv(1,1); build(); int Q; scanf("%d",&Q); int t,a,b; while(Q--){ scanf("%d%d%d",&t,&a,&b); if(t == 1) rvPath(a,b); else if(t == 2) rvAdj(a,b); else if(t == 3) printf("%d\n", query(a,b)); } } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif //cout<<log2(maxn); int T; scanf("%d",&T); while(T--){ init(); solve(); } return 0; }
时间: 2024-10-06 06:20:14