BZOJ 3786:星系探索
Portal:http://www.lydsy.com/JudgeOnline/problem.php?id=3786
解析:
我们先跑出树的括号序,对于位置\(L_i\)结点值设为\(A_i\),位置\(R_i\)结点值为\(-A_i\),则一个结点到父节点的值即为\(\sum_1^{L_i} s_i\),现在问题就变成了如何维护这个序列和如何快速求和。
我们用一棵splay来维护整个序列,需要维护splay结点的子树和,子树正负数个数,下放标记,然后改父节点直接移动一下区间,加值直接区间赋值,求和就分离出目标区间求和即可。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
typedef long long LL;
const int maxn=300000+23;
struct Node{
Node *ch[2],*f;
int v,size;
LL s,sum,tag,ab; //I'm going to be mad!!
Node(int val,Node *null) {v=val,s=0,sum=0,ab=0,size=1,tag=0,ch[0]=ch[1]=f=null;}
void maintain()
{
size=ch[0]->size+ch[1]->size+1;
sum=ch[0]->sum+ch[1]->sum+s;
ab=ch[0]->ab+ch[1]->ab+((v<0)?(-1):(1));
}
void pushdown()
{
if (tag) ch[0]->update(tag),ch[1]->update(tag),tag=0;
}
void update(LL val)
{
s+=((v<0)?(-1):(1))*val,sum+=ab*val;
if (size>1) tag+=val;
}
int cmp(int k)
{
if ((ch[0]->size+1)==k) return -1;
return (ch[0]->size>=k)?(0):(1);
}
} *root,*null,*x,*y,*z,*w,*L[maxn],*R[maxn];
Node *newnode(int v) {return new Node(v,null);}
//------------------------------------------
int n,m,k,v[maxn],vs,l,r,ind,last;
LL a[maxn],val;
vector<int> G[maxn];
char c[10];
//-----------------------------
Node *rotate(Node* &o,int d)
{
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d],o->ch[d^1]->f=o;
k->ch[d]=o,o->f=k;
o->maintain(),k->maintain();o=k;
}
void splay(Node* &o,int k)
{
o->pushdown();int d=o->cmp(k);
if (d==1) k-=o->ch[0]->size+1;
if (d!=-1)
{
Node* p=o->ch[d];p->pushdown();
int d2=p->cmp(k),k2=(d2==0)?(k):(k-p->ch[0]->size-1);
if (d2!=-1)
{
splay(p->ch[d2],k2);
if (d==d2) rotate(o,d^1); else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
Node* merge(Node *x,Node *y)
{
if (x==null) return y;
if (y==null) return x;
splay(x,x->size);
x->ch[1]=y,y->f=x,x->maintain();
return x;
}
void split(Node *o,int k,Node* &l,Node* &r)
{
if (k<=0) {l=null,r=o;return;}
splay(o,k);
l=o,r=o->ch[1],l->f=r->f=null,o->ch[1]=null,l->maintain();
}
void rnk(Node *o,int &ans,int d)
{
if (o==null) return;
if (d==1) ans+=o->ch[0]->size+1;
rnk(o->f,ans,(o->f->ch[0]==o)?(0):(1));
}
//-----------------------------
Node* Build(int l,int r,Node* f)
{
if (l>r) return null;
int mid=(l+r)>>1;
Node *o=newnode(v[mid]);
o->f=f,o->ch[0]=Build(l,mid-1,o),o->ch[1]=Build(mid+1,r,o);
if (v[mid]>0) L[v[mid]]=o,o->s=a[v[mid]]; else R[-v[mid]]=o,o->s=-a[-v[mid]];
o->maintain();
return o;
}
void trans(int k)
{
v[++vs]=k;
rep(i,0,sz(G[k])-1) trans(G[k][i]);
v[++vs]=-k;
}
int main()
{
scanf("%d",&n);
rep(i,2,n)
{
scanf("%d",&k);
G[k].push_back(i);
}
rep(i,1,n) scanf("%d",&a[i]);
trans(1);
null=newnode(0),null->size=0,null->s=null->sum=null->ab=0,root=null;
root=Build(1,vs,null);
scanf("%d",&m);
rep(i,1,m)
{
scanf("%s",c+1);
if (c[1]=='Q')
{
scanf("%d",&k);
last=0,rnk(L[k],last,1);
split(root,last,x,y);
printf("%lld\n",x->sum);
root=merge(x,y);
}
if (c[1]=='F')
{
scanf("%d%lld",&ind,&val);
l=0,rnk(L[ind],l,1),r=0,rnk(R[ind],r,1);
split(root,l-1,x,y);
split(y,r-l+1,z,w);
z->update(val);
root=merge(x,merge(z,w));
}
if (c[1]=='C')
{
scanf("%d%d",&ind,&k);
l=0,rnk(L[ind],l,1),r=0,rnk(R[ind],r,1);
split(root,l-1,x,y);
split(y,r-l+1,z,w);
root=merge(x,w);
last=0,rnk(R[k],last,1);
split(root,last-1,x,y);
root=merge(x,merge(z,y));
}
}
return 0;
}