Description
物理学家小C的研究正遇到某个瓶颈。
他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球。主星球没有依赖星球。
我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c.
对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的。并且从星球a出发只能直接到达它的依赖星球b.
每个星球i都有一个能量系数wi.小C想进行若干次实验,第i次实验,他将从飞船上向星球di发射一个初始能量为0的能量收集器,能量收集器会从星球di开始前往主星球,并收集沿途每个星球的部分能量,收集能量的多少等于这个星球的能量系数。
但是星系的构成并不是一成不变的,某些时刻,星系可能由于某些复杂的原因发生变化。
有些时刻,某个星球能量激发,将使得所有依赖于它的星球以及他自己的能量系数均增加一个定值。还有可能在某些时刻,某个星球的依赖星球会发生变化,但变化后依然满足依赖关系是无环的。
现在小C已经测定了时刻0时每个星球的能量系数,以及每个星球(除了主星球之外)的依赖星球。接下来的m个时刻,每个时刻都会发生一些事件。其中小C可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。
Solution
本题非常卡常数,一开始直接扒3153的代码狂T不止,改写Splay后也是狂T不止,最后把Splay从数组储存改成结构体储存才AC。 ———Claris
涨姿势题。。
用Splay维护一个dfs序,这个dfs序是那种进入也算,出去也算的dfs序
然后进入的算负的,出去的算正的,这样可以保证对于一个点正dfs序到根的正dfs序之间数字的和恰好是那条路径的权值(不是路径上的要不不出现在这段dfs序中,要不出现了2次,一次正一次负恰好抵消对答案无影响)。
然后就是Splay的板子啦
Code
这是那个结构体版的
/**************************************************************
Problem: 3786
User: bblss123
Language: C++
Result: Accepted
Time:23772 ms
Memory:14004 kb
****************************************************************/
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<time.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define fi first
#define se second
#define pb push_back
#define ph push
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)
const int INF=(ud)-1>>1;
const ll inf=(ull)-1>>1;
template<class T>void rd(T &a){
a=0;char c;
while(c=getchar(),c<48);
do a=a*10+(c^48);
while(c=getchar(),c>47);
}
inline void rdc(char &c){
c=0;char s;
while(s=getchar(),s<65);
c=s;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar(48+x%10);
}
template<class T>void pt(T x){
if(!x)putchar('0');
else nt(x);
}
template<class T>void Max(T &a,T b){
if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
if(a==-1||a>b)a=b;
}
const int M=2e5+10;
const int N=1e5+2;
int f[N],w[N];
struct Edge{
int to,nxt;
}G[N];
int tot_edge,head[N];
inline void add_edge(int from,int to){
G[tot_edge]=(Edge){to,head[from]};
head[from]=tot_edge++;
}
struct Splay_Tree{
struct node{
int tr[2],fa,sz,pos;
ll sum,add,val;
inline node(){
tr[0]=tr[1]=sum=add=val=fa=sz=pos=0;
}
}T[M];
int que[M],allc,rt;
inline void up(int &x){
node &l=T[T[x].tr[0]],&r=T[T[x].tr[1]];
T[x].sz=l.sz+r.sz+1;
T[x].sum=l.sum+r.sum+T[x].val;
T[x].pos=l.pos+r.pos+(x<=N);
}
inline void down(int &x){
if(!T[x].add)return;
ll &ad=T[x].add;
T[x].val+=x>=N?-ad:ad;
node &l=T[T[x].tr[0]],&r=T[T[x].tr[1]];
l.add+=T[x].add,r.add+=T[x].add;
int nagl=l.sz-l.pos,nagr=r.sz-r.pos;
l.sum+=1ll*l.pos*ad-1ll*nagl*ad;
r.sum+=1ll*r.pos*ad-1ll*nagr*ad;
ad=0;
}
inline void rotate(int x,int &k){
int y=T[x].fa,z=T[y].fa,r=T[y].tr[0]==x,l=r^1;
if(y==k)k=x;
else{
if(T[z].tr[0]==y)T[z].tr[0]=x;
else T[z].tr[1]=x;
}
T[x].fa=z,T[y].fa=x,T[T[x].tr[r]].fa=y;
T[y].tr[l]=T[x].tr[r],T[x].tr[r]=y;
up(y);
}
inline void Splay(int x,int &k){
for(int v=x;v!=rt;v=T[v].fa)que[++allc]=v;
que[++allc]=rt;
for(;allc;)down(que[allc--]);
for(;x!=k;){
int y=T[x].fa,z=T[y].fa;
if(y!=k){
if(T[z].tr[0]==y^T[y].tr[0]==x)rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
up(x);
}
inline void Insert(int x,int w){
T[x].val=w;
if(!rt)rt=x;
else T[rt].tr[1]=x,T[x].fa=rt,up(x),Splay(x,rt);
}
inline ll query(int &x){
Splay(x,rt);
return T[T[x].tr[0]].sum+T[x].val;
}
inline int search(int x,const bool &dir){
if(!T[x].tr[dir])return x;
return search(T[x].tr[dir],dir);
}
inline void Change(int x,int y){//turn x's father to y
Splay(x,rt);
int k1=search(T[rt].tr[0],1);
Splay(x+N,rt);
int k2=search(T[rt].tr[1],0);
Splay(k1,rt),Splay(k2,T[rt].tr[1]);
int w=T[k2].tr[0];
T[k2].tr[0]=0,T[w].fa=0;
Splay(y,rt);
int k=search(T[y].tr[1],0);
Splay(k,T[y].tr[1]);
T[w].fa=k,T[k].tr[0]=w;
}
inline void Add(int x,int w){
Splay(x,rt);
int k1=search(T[rt].tr[0],1);
Splay(x+N,rt);
int k2=search(T[rt].tr[1],0);
Splay(k1,rt),Splay(k2,T[rt].tr[1]);
int s=T[k2].tr[0];
T[s].add+=w,T[s].sum+=1ll*w*T[s].pos-1ll*(T[s].sz-T[s].pos)*w;
}
}spt;
int dfs_clock;
inline void dfs(int v){
spt.Insert(v+1,w[v]);
for(int i=head[v];~i;i=G[i].nxt)
dfs(G[i].to);
spt.Insert(v+N+1,-w[v]);
}
int main(){
int n,q,u,v;cin>>n;
memset(head,-1,sizeof(head));
tot_edge=0;
for(int i=2;i<=n;++i)
rd(f[i]),add_edge(f[i],i);
for(int i=1;i<=n;++i)rd(w[i]);
spt.Insert(1,0);
dfs(1);
spt.Insert(N<<1|1,0);
char c;
for(cin>>q;q--;){
rdc(c);
switch(c){
case('Q'):
rd(v),++v;
pt(spt.query(v)),putchar('\n');
break;
case('C')://turn u's father to v
rd(u),rd(v),++u,++v;
spt.Change(u,v);
break;
case('F'):
rd(u),rd(v);++u;
spt.Add(u,v);
break;
}
}
return 0;
}
还有数组版。。
/**************************************************************
Problem: 3786
User: bblss123
Language: C++
Result: Time_Limit_Exceed
****************************************************************/
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<time.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define fi first
#define se second
#define pb push_back
#define ph push
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)
const int INF=(ud)-1>>1;
const ll inf=(ull)-1>>1;
template<class T>void rd(T &a){
a=0;char c;
while(c=getchar(),c<48);
do a=a*10+(c^48);
while(c=getchar(),c>47);
}
inline void rdc(char &c){
c=0;char s;
while(s=getchar(),s<65);
c=s;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar(48+x%10);
}
template<class T>void pt(T x){
if(!x)putchar('0');
else nt(x);
}
template<class T>void Max(T &a,T b){
if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
if(a==-1||a>b)a=b;
}
const int M=2e5+10;
const int N=1e5+2;
int f[N],w[N];
struct Edge{
int to,nxt;
}G[N];
int tot_edge,head[N];
inline void add_edge(int from,int to){
G[tot_edge]=(Edge){to,head[from]};
head[from]=tot_edge++;
}
struct Splay_Tree{
int tr[M][2],rt,fa[M],que[M],sz[M],allc,pos[M];
ll sum[M],add[M],val[M];
inline void up(int &x){
sz[x]=sz[tr[x][0]]+sz[tr[x][1]]+1;
sum[x]=sum[tr[x][0]]+sum[tr[x][1]]+val[x];
pos[x]=pos[tr[x][0]]+pos[tr[x][1]]+(x<=N);
}
inline void down(int &x){
if(!add[x])return;
val[x]+=x>=N?-add[x]:add[x];
int l=tr[x][0],r=tr[x][1];
add[l]+=add[x],add[r]+=add[x];
int nagl=sz[l]-pos[l],nagr=sz[r]-pos[r];
sum[tr[x][0]]+=1ll*pos[l]*add[x]-1ll*nagl*add[x];
sum[tr[x][1]]+=1ll*pos[r]*add[x]-1ll*nagr*add[x];
add[x]=0;
}
inline void rotate(int x,int &k){
int y=fa[x],z=fa[y],r=tr[y][0]==x,l=r^1;
if(y==k)k=x;
else{
if(tr[z][0]==y)tr[z][0]=x;
else tr[z][1]=x;
}
fa[x]=z,fa[y]=x,fa[tr[x][r]]=y;
tr[y][l]=tr[x][r],tr[x][r]=y;
up(y);
}
inline void Splay(int x,int &k){
for(int v=x;v!=rt;v=fa[v])que[++allc]=v;
que[++allc]=rt;
for(;allc;)down(que[allc--]);
for(;x!=k;){
int y=fa[x],z=fa[y];
if(y!=k){
if(tr[z][0]==y^tr[y][0]==x)rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
up(x);
}
inline void Insert(int x,int w){
val[x]=w;
if(!rt)rt=x;
else tr[rt][1]=x,fa[x]=rt,up(x),Splay(x,rt);
}
inline ll query(int &x){
Splay(x,rt);
return sum[tr[x][0]]+val[x];
}
inline int search(int x,const bool &dir){
if(!tr[x][dir])return x;
return search(tr[x][dir],dir);
}
inline void Change(int x,int y){//turn x's father to y
Splay(x,rt);
int k1=search(tr[rt][0],1);
Splay(x+N,rt);
int k2=search(tr[rt][1],0);
Splay(k1,rt),Splay(k2,tr[rt][1]);
int w=tr[k2][0];
tr[k2][0]=0,fa[w]=0;
Splay(y,rt);
int k=search(tr[y][1],0);
Splay(k,tr[y][1]);
fa[w]=k,tr[k][0]=w;
}
inline void Add(int x,int w){
Splay(x,rt);
int k1=search(tr[rt][0],1);
Splay(x+N,rt);
int k2=search(tr[rt][1],0);
Splay(k1,rt),Splay(k2,tr[rt][1]);
int s=tr[k2][0];
add[s]+=w,sum[s]+=1ll*w*pos[s]-1ll*(sz[s]-pos[s])*w;
}
}spt;
int dfs_clock;
inline void dfs(int v){
spt.Insert(v+1,w[v]);
for(int i=head[v];~i;i=G[i].nxt)
dfs(G[i].to);
spt.Insert(v+N+1,-w[v]);
}
int main(){
int n,q,u,v;cin>>n;
memset(head,-1,sizeof(head));
tot_edge=0;
for(int i=2;i<=n;++i)
rd(f[i]),add_edge(f[i],i);
for(int i=1;i<=n;++i)rd(w[i]);
spt.Insert(1,0);
dfs(1);
spt.Insert(N<<1|1,0);
char c;
for(cin>>q;q--;){
rdc(c);
switch(c){
case('Q'):
rd(v),++v;
pt(spt.query(v)),putchar('\n');
break;
case('C')://turn u's father to v
rd(u),rd(v),++u,++v;
spt.Change(u,v);
break;
case('F'):
rd(u),rd(v);++u;
spt.Add(u,v);
break;
}
}
return 0;
}
卡常数又到了一个新境界