题解:P5773 [JSOI2016] 轻重路径
_AyachiNene · · 题解
不用脑子的纯数据结构做法。
思路:
考虑把一次删点作为一次链修改,动态维护重链。首先容易发现的是,一次修改最多改变
由于作者是奶龙,误以为 lct 是单
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IO
{
char buff[1<<21],*p1=buff,*p2=buff;
char getch(){return p1==p2&&(p2=((p1=buff)+fread(buff,1,1<<21,stdin)),p1==p2)?EOF:*p1++;}
template<typename T>void read(T &x){char ch=getch();int fl=1;x=0;while(ch>'9'||ch<'0'){if(ch=='-')fl=-1;ch=getch();}while(ch<='9'&&ch>='0'){x=x*10+ch-48;ch=getch();}x*=fl;}
template<typename T>void read_s(T &x){x="";char ch=getch();while(!(ch>='a'&&ch<='z')&&!(ch>='A'&&ch<='Z'))ch=getch();while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){x+=ch;ch=getch();}}
template<typename T,typename ...Args>void read(T &x,Args& ...args){read(x);read(args...);}
char obuf[1<<21],*p3=obuf;
void putch(char ch) {if(p3-obuf<(1<<21))*p3++=ch;else fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=ch;}
char cha[100];
template<typename T>void write(T x) {if(!x)return putch('0');if(x<0)putch('-'),x*=-1;int top=0;while(x)cha[++top]=x%10+48,x/=10;while(top)putch(cha[top]),top--;}
template<typename T,typename ...Args>void write(T x,Args ...args) {write(x);putch(' ');write(args...);}
void put(string s){for(int i=0;i<s.size();i++)putch(s[i]);}
void flush(){fwrite(obuf,p3-obuf,1,stdout);}
}
using namespace IO;
int n,m;
int e[200005][2];
int ans;
int f[200005],son[200005],dep[200005],siz[200005],dfn[200005],top[200005],cnt;
namespace Nene
{
struct splt
{
int ch[2],f,tag,fmn,fmx,tp;
int val,mn;
int top,bot;
}t[200005];
inline int isroot(int p){return t[t[p].f].ch[0]!=p&&t[t[p].f].ch[1]!=p;}
inline void update(int p)
{
t[p].mn=t[p].val;
if(t[p].ch[0]) t[p].mn=min(t[p].mn,t[t[p].ch[0]].mn);
if(t[p].ch[1]) t[p].mn=min(t[p].mn,t[t[p].ch[1]].mn);
t[p].fmn=t[p].tp;
if(t[p].ch[0]) t[p].fmn=min(t[p].fmn,t[t[p].ch[0]].fmn);
if(t[p].ch[1]) t[p].fmn=min(t[p].fmn,t[t[p].ch[1]].fmn);
t[p].fmx=max({t[p].tp,t[t[p].ch[0]].fmx,t[t[p].ch[1]].fmx});
t[p].top=t[p].bot=p;
if(t[p].ch[0]) t[p].top=t[t[p].ch[0]].top;
if(t[p].ch[1]) t[p].bot=t[t[p].ch[1]].bot;
}
inline void push(int p,int v){t[p].tag+=v;t[p].val+=v;t[p].mn+=v;}
inline void down(int p)
{
if(!t[p].tag) return;
if(t[p].ch[0]) push(t[p].ch[0],t[p].tag);
if(t[p].ch[1]) push(t[p].ch[1],t[p].tag);
t[p].tag=0;
}
int stk[200005],top; //注意不要把splay用的栈和记要改的点的搞混了
int del[200005],cnt;
inline void rotate(int p)
{
int f=t[p].f,ff=t[f].f;
int k=t[t[p].f].ch[1]==p;
if(!isroot(f)) t[ff].ch[t[ff].ch[1]==f]=p;t[p].f=ff;
t[f].ch[k]=t[p].ch[k^1];t[t[p].ch[k^1]].f=f;
t[p].ch[k^1]=f;t[f].f=p;
update(f);update(p);
}
inline void splay(int p)
{
stk[++top]=p;
for(int i=p;!isroot(i);i=t[i].f) stk[++top]=t[i].f;
while(top) down(stk[top--]);
while(!isroot(p))
{
int f=t[p].f,ff=t[f].f;
if(!isroot(f)) (t[f].ch[1]==p)^(t[ff].ch[1]==f)?rotate(p):rotate(f);
rotate(p);
}
}
void print(int p)
{
if(!p) return;
down(p);
print(t[p].ch[0]);
cout<<p<<" "<<t[p].val<<endl;
print(t[p].ch[1]);
}
void change(int p) //链修改
{
if(!p) return;
down(p); //记得下传
if(t[p].fmn) return/* del[++cnt]=t[p].bot,*/void();
if(!t[p].tp) del[++cnt]=f[p],del[++cnt]=f[p];
change(t[p].ch[0]);change(t[p].ch[1]);
update(p);
}
void dfs(int p)
{
if(!p) return;
down(p); //记得下传
if(t[p].mn>=0) return;
if(t[p].val==-1) del[++cnt]=p;
dfs(t[p].ch[0]);dfs(t[p].ch[1]);
}
inline void access(int p)
{
if(!e[f[p]][0]||!e[f[p]][1]) ans-=p; //特判一条链的最后一个点
int tmp=p,pre=0;
for(pre;p;pre=p,p=t[p].f) splay(p),t[p].ch[1]=pre,update(p);
push(pre,-1);del[++cnt]=t[pre].bot;del[++cnt]=-f[t[pre].top];
change(pre);
while(cnt)
{
int x=del[cnt--];
// cout<<x<<endl;
if(!x) continue;
if(x<0) splay(-x),--t[-x].val; //修改记得splay
else splay(x),++t[x].val;
update(abs(x));
}
splay(pre);dfs(pre); //跟在上面变了,记得splay回来
while(cnt)
{
int x=del[cnt--];
splay(x);t[x].val=1;update(x);
ans+=t[e[x][0]].tp?-e[x][0]+e[x][1]:e[x][0]-e[x][1];
if(e[x][0]) splay(e[x][0]),t[e[x][0]].tp^=1,update(e[x][0]); //同样的,修改记得splay
if(e[x][1]) splay(e[x][1]),t[e[x][1]].tp^=1,update(e[x][1]);
}
// splay(pre);print(pre);cout<<endl;
e[f[tmp]][e[f[tmp]][1]==tmp]=0; //断边,不断也无所谓,但写都写lct了你不断?
splay(tmp);t[tmp].ch[0]=t[t[tmp].ch[0]].f=0;
}
}using namespace Nene;
void dfs1(int u,int fa)
{
f[u]=fa;dep[u]=dep[fa]+1;siz[u]=1;t[u].f=fa;
t[u].val=1e9;
for(int i=0;i<=1;i++)
{
int v=e[u][i];
if(!v) continue;
dfs1(v,u);siz[u]+=siz[v];
if(siz[e[u][son[u]]]<siz[v]) son[u]=i;
}
if(e[u][son[u]]) t[e[u][son[u]]].tp=1,t[u].val=siz[e[u][son[u]]]-siz[e[u][son[u]^1]];
else t[u].val=1e9; //叶子特判
update(e[u][son[u]]);update(u);
ans+=e[u][son[u]];
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n);
for(int i=1;i<=n;i++) read(e[i][0],e[i][1]);
dfs1(1,0);
read(m);
write(ans),putch('\n');
while(m--)
{
int p;read(p);
access(p);
write(ans),putch('\n');
}
flush();
return 0;
}