SHOI2014 三叉神经树
一道非常好的LCT/树剖题。但是像我这样的菜鸡想不到什么有效做法……
首先我们可以很容易发现,一次如果要在链上连续修改那么肯定是从底向上的一端连续区间。如果我们把每个节点的输入值作为其权值,那么会被连续更改的一定是一端连续的为1或者为2的区间。
那么我们就可以通过维护这个区间来解决这道题。如何维护?有一种做法是直接二分深度最大的非1/2的点在哪。不过这个似乎比较麻烦……我们直接维护这个链上深度最深的,非1/2的点的位置。具体怎么维护呢?在\(pushup\)的时候,我们顺便更新。首先用自己的右儿子更新(深度更大,肯定更优秀),如果不行就用自己,还不行才用左儿子(深度比较小)
之后具体在处理的时候,我们就是一个标准的LCT操作了。这个题中根始终为1,不需要换根,也不需要\(link\),\(cut\)。在修改的时候打通到那个点的路径,之后判断一下是否存在非1/2的点,之后根据情况单点/区间修改即可。
思路来源于\(FlashHu\)大佬。看一下代码。
#include<bits/stdc++.h>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar('\n')
#define I inline
using namespace std;
typedef long long ll;
const int M = 2000005;
I int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
struct edge
{
int next,to;
}e[M<<1];
int ch[M][2],fa[M],val[M],tag[M],num1[M],num2[M],sta[M],top,head[M],ecnt,x,y,z,n,q,ans;
void add(int x,int y) {e[++ecnt] = (edge){head[x],y},head[x] = ecnt;}
bool nroot(int x) {return (ch[fa[x]][0] == x) || (ch[fa[x]][1] == x);}
bool get(int x) {return ch[fa[x]][1] == x;}
void modify(int x,int d) {val[x] ^= 3,swap(num1[x],num2[x]),tag[x] += d;}
void pushdown(int x){if(tag[x]) modify(ch[x][0],tag[x]),modify(ch[x][1],tag[x]),tag[x] = 0;}
void pushup(int x)
{
num1[x] = num1[ch[x][1]];
if(!num1[x] && val[x] != 1) num1[x] = x;
if(!num1[x]) num1[x] = num1[ch[x][0]];
num2[x] = num2[ch[x][1]];
if(!num2[x] && val[x] != 2) num2[x] = x;
if(!num2[x]) num2[x] = num2[ch[x][0]];
}
void rotate(int x)
{
int y = fa[x],z = fa[y],k = get(x);
if(nroot(y)) ch[z][get(y)] = x;
fa[x] = z,ch[y][k] = ch[x][k^1],fa[ch[x][k^1]] = y;
ch[x][k^1] = y,fa[y] = x;
pushup(y),pushup(x);
}
void splay(int x)
{
int p = x;sta[++top] = p;
while(nroot(p)) p = fa[p],sta[++top] = p;
while(top) pushdown(sta[top--]);
while(nroot(x))
{
int y = fa[x],z = fa[y];
if(nroot(y)) ((ch[y][0] == x) ^ (ch[z][0] == y)) ? rotate(x) : rotate(y);
rotate(x);
}
}
void access(int x) {for(int g = 0;x;g = x,x = fa[x]) splay(x),ch[x][1] = g,pushup(x);}
void dfs(int x) {for(int i = head[x];i;i = e[i].next) dfs(e[i].to),val[x] += (val[e[i].to] >> 1);}
int main()
{
n = read();
rep(i,1,n) x = read(),y = read(),z = read(),fa[x] = fa[y] = fa[z] = i,add(i,x),add(i,y),add(i,z);
rep(i,1,(n<<1)+1) x = read(),val[i+n] = x << 1;
dfs(1),q = read(),ans = val[1] >> 1;
//rep(i,1,n*3+1) printf("%d ",val[i]);enter;
while(q--)
{
x = read(),val[x] ^= 2;
int k = val[x] - 1;
x = fa[x],access(x),splay(x);
int p = (~k) ? num1[x] : num2[x];
//rep(i,1,n*3+1) printf("#%d ",num1[i]);enter;
//rep(i,1,n*3+1) printf("!%d ",num2[i]);enter;
//printf("%d\n",p);
if(!p) modify(x,k),pushup(x),ans ^= 1;
else splay(p),modify(ch[p][1],k),pushup(ch[p][1]),val[p] += k,pushup(p);
printf("%d\n",ans);
}
return 0;
}
当你意识到,每个上一秒都成为永恒。