题解:P10214 [CTS2024] 投票游戏
很有意思的黑题,每一步都很自然。
思路
首先考虑如何比较两个点的删除时间,发现可以通过比较两个点删除时的票数来进行比较我们设
那么如果
注意到这是一个树形结构,每个人只会影响其祖先的票数,每个人的初始票数为
考虑优化,每次修改是影响点
::::info[code]
#include <bits/stdc++.h>
#define pii pair<int,int>
#define pb emplace_back
#define mid ((l+r)>>1)
#define int long long
#define mk make_pair
#define rs now<<1|1
#define ls now<<1
#define reaD read
#define raed read
#define haed head
#define cotu cout
#define se second
#define fi first
#define itn int
using namespace std;
bool Mst;
const int Max=2e5+10;
const int mod=998244353;
const int inf=1e18+10;
inline int read(){
int res=0,v=1;
char c=getchar();
while(c<'0'||c>'9'){v=(c=='-'?-1:1);c=getchar();}
while(c>='0'&&c<='9'){res=(res<<3)+(res<<1)+(c^48);c=getchar();}
return res*v;
}
int b[Max],dp[Max],sumb[Max];
int root[Max],Val[Max],n;
struct tree{
int minn,sum,ch[2],key;
#define ch(x,i) tr[x].ch[i]
#define minn(x) tr[x].minn
#define sum(x) tr[x].sum
#define key(x) tr[x].key
}tr[Max];
struct FHQ{ //平衡树编号与树的编号对应,方便处理
void pushup(int now){
sum(now)=sum(ch(now,0))+b[now]+sum(ch(now,1));
minn(now)=min(minn(ch(now,0)),min(sum(ch(now,0))+dp[now],sum(ch(now,0))+b[now]+minn(ch(now,1))));
}
void Split(int now,pii val,int &x,int &y){
if(!now){x=y=0;return;}
if(dp[now]>val.fi||(dp[now]==val.fi&&now>val.se)){
x=now;
Split(ch(now,1),val,ch(x,1),y);
}else{
y=now;
Split(ch(now,0),val,x,ch(y,0));
}
pushup(now);
}
int merge(int x,int y){
if(!x||!y)return x|y;
if(key(x)>key(y)){
ch(x,1)=merge(ch(x,1),y);
pushup(x);return x;
}else{
ch(y,0)=merge(x,ch(y,0));
pushup(y);return y;
}
}
int Query(int now,int val){
if(!now)return val;
if(minn(ch(now,0))<val)return Query(ch(now,0),val);
else if(sum(ch(now,0))+dp[now]<val)return val-sum(ch(now,0));
else return Query(ch(now,1),val-sum(ch(now,0))-b[now]);
}
void insert(int x,int y){
int xx,yy;
Split(root[x],mk(dp[y],y),xx,yy);
minn(y)=dp[y],sum(y)=b[y];key(y)=rand();
root[x]=merge(xx,merge(y,yy));
}
void Del(int x,int y){
int xx,yy,zz;
Split(root[x],mk(dp[y],y),xx,yy);
Split(yy,mk(dp[y],y-1),yy,zz);root[x]=merge(xx,zz);
}
}t1;
struct Sg{
int lim,x,y;//小于lim返回x,否则返回y
Sg(int lim=0,int x=0,int y=0):
lim(lim),x(x),y(y){;}
int chk(int z){return z<lim?x:y;}
Sg operator +(Sg b){return Sg(lim,b.chk(x),b.chk(y));}
}f[Max]; //每个点的函数
struct SGT{ //线段树维护分段函数。
Sg tr[Max<<2];
void pushup(int now){
tr[now]=tr[now<<1|1]+tr[now<<1];
}
void Modify(int now,int l,int r,int to,Sg val){
if(l==r){tr[now]=val;return;}
if(to<=mid)Modify(ls,l,mid,to,val);
else Modify(rs,mid+1,r,to,val);
pushup(now);
}
Sg Query(int now,int l,int r,int L,int R){
if(L<=l&&R>=r)return tr[now];
if(R<=mid)return Query(ls,l,mid,L,R);
if(L>mid)return Query(rs,mid+1,r,L,R);
return Query(rs,mid+1,r,L,R)+Query(ls,l,mid,L,R);
}
}t2;
struct Node{
int to,next;
Node(int to=0,int next=0):
to(to),next(next){;}
}a[Max<<1];
int head[Max],cnt;
void add(int x,int y){
a[++cnt]=Node(y,head[x]);
head[x]=cnt;
}
struct Tree{
int siz,son,dep,fa,id,end,top;
#define siz(x) bbb[x].siz
#define top(x) bbb[x].top
#define son(x) bbb[x].son
#define dep(x) bbb[x].dep
#define end(x) bbb[x].end
#define id(x) bbb[x].id
#define fa(x) bbb[x].fa
}bbb[Max];
Sg Queryf(int now){
if(!son(now))return Sg(0,0,Val[now]);
int val=t1.Query(root[now],Val[now]+sumb[now]); //轻儿子的值。
return Sg(val,val,t1.Query(root[now],Val[now]+sumb[now]-b[son(now)]));
}
void dfs1(int now,int fa){
siz(now)=1;fa(now)=fa;dep(now)=dep(fa)+1;
for(int i=head[now];i;i=a[i].next){
int to=a[i].to;
if(to==fa)continue;
sumb[now]+=b[to];
dfs1(to,now);siz(now)+=siz(to);
son(now)=siz(son(now))>siz(to)?son(now):to;
}
for(int i=head[now];i;i=a[i].next){
int to=a[i].to;
if(to==fa||to==son(now))continue;
t1.insert(now,to);
}
f[now]=Queryf(now);dp[now]=f[now].chk(dp[son(now)]);
}
int Res=0;
void dfs2(int now,int top){
id(now)=++Res;top(now)=top;t2.Modify(1,1,n,id(now),f[now]);
if(son(now)){
dfs2(son(now),top);end(now)=end(son(now));
}else end(now)=now; //记录链底
for(int i=head[now];i;i=a[i].next){
int to=a[i].to;
if(!id(to))dfs2(to,to);
}
}
void work(int x,int opt=-1){
t1.Del(fa(x),x);
if(opt!=-1)b[x]=opt;
dp[x]=t2.Query(1,1,n,id(x),id(end(x))).chk(0);
t1.insert(fa(x),x);
}
void Modify(int x){
while(x){
f[x]=Queryf(x);t2.Modify(1,1,n,id(x),f[x]);
x=top(x);
if(x!=1){work(x);}
else return ;
x=fa(x);
}
}
bool Med;
signed main(){n=read();
n=read();int q=read();
for(int i=2;i<=n;++i)add(read(),i);
for(int i=1;i<=n;++i)Val[i]=read();
for(int i=1;i<=n;++i)b[i]=read();
minn(0)=inf;
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=q;++i){
int opt=read();
if(opt==1){
int p,x,y;
p=read(),x=read(),y=read();
Val[p]=x;Modify(p);
if(p!=1){
sumb[fa(p)]-=b[p];sumb[fa(p)]+=y;
if(p!=son(fa(p)))work(p,y);
b[p]=y;
Modify(fa(p));
}
}else{
int x,y;
x=read(),y=read();
int tag=x>y;
x=t2.Query(1,1,n,id(x),id(end(x))).chk(0);
y=t2.Query(1,1,n,id(y),id(end(y))).chk(0);
if(x>y||((x==y)&&(tag)))cout << 0 << "\n";
else cout << 1 << "\n";
}
}
cerr<< "Time: "<<clock()/1000.0 << "s\n";
cerr<< "Memory: " << (&Med-&Mst)/1000000.0 << "MB\n";
return 0;
}
::::