SCOI2015 情報傳遞
阿新 • • 發佈:2018-12-13
Link
Diffculty
演算法難度6,思維難度6,程式碼難度6
Description
由於原版題面有點兒複雜,我會簡化許多。
給定一棵 個點的樹,每個點初始權值為 ,每個點有一個開關,如果開關開著,這個點的權值會每天加 。
有 個操作,分為兩種:
- 開啟一個點 的開關,保證這個操作對每個點至多進行一次。
- 查詢 到 的路徑上有多少個點權值大於
Solution
我們考慮在什麼情況下,修改 會對詢問 造成貢獻。
假設詢問 的限制為 ,那麼滿足 即可。
其中 為修改 對應的點在第 天的權值。
我們對式子變形可得 ,這樣我們可以轉化問題了。
開啟開關相當於將這個點權值設為 ,查詢相當於查詢權值小於 的點的個數。
這個問題我們可以整體二分+樹狀陣列。
整體二分之後,我們可以忽略權值的影響了,直接變成單點加,鏈上求和。
這個問題我們差分之後,就變成了子樹加,單點求值了,這個可以簡單地用dfs序上建立樹狀陣列來維護。
我們得到了一個 的做法,實際上有更優的做法,我這裡不多做介紹。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=2e5+5;
int n,m,tot,root,cnt;
int head[N],to[N<<1],Next[N<<1];
inline void addedge(int x,int y){
to[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
int dfn[N],ed[N],dfn_clock;
int st[N][18],dep[N];
inline void dfs(int x,int fa){
dfn[x]=++dfn_clock;
st[x][0]=fa;
dep[x]=dep[fa]+1;
for(int i=1;i<=17;++i)st[x][i]=st[st[x][i-1]][i-1];
for(int i=head[x];i;i=Next[i]){
int u=to[i];
if(u==fa)continue;
dfs(u,x);
}
ed[x]=dfn_clock;
}
inline int getlca(int x,int y){
if(x==y)return x;
if(dep[x]<dep[y])swap(x,y);
for(int i=17;i>=0;--i)
if(dep[st[x][i]]>=dep[y])
x=st[x][i];
if(x==y)return x;
for(int i=17;i>=0;--i)
if(st[x][i]!=st[y][i])
x=st[x][i],y=st[y][i];
return st[x][0];
}
int t[N];
inline void modify(int x,int v){
while(x<=n){
t[x]+=v;
x+=x&-x;
}
}
inline int query(int x){
int ans=0;
while(x){
ans+=t[x];
x-=x&-x;
}
return ans;
}
int ans1[N],ans2[N];
struct data{
int id,opt,x,y,v,lca;
data(){}
data(int _id,int _opt,int _x,int _y,int _v,int _lca)
:id(_id),opt(_opt),x(_x),y(_y),v(_v),lca(_lca){}
};
vector<data> q;
inline void solve(vector<data> &t,int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
for(vector<data>::iterator it=t.begin();it!=t.end();++it){
if((*it).opt==1 && (*it).v>mid){
int num=-query(dfn[(*it).lca]);
num-=query(dfn[st[(*it).lca][0]]);
num+=query(dfn[(*it).x]);
num+=query(dfn[(*it).y]);
ans2[(*it).id]+=num;
}
else if((*it).opt==2 && (*it).v<=mid){
modify(dfn[(*it).x],1);
modify(ed[(*it).x]+1,-1);
}
}
for(vector<data>::iterator it=t.begin();it!=t.end();++it){
if((*it).opt==2 && (*it).v<=mid){
modify(dfn[(*it).x],-1);
modify(ed[(*it).x]+1,1);
}
}
vector<data> ls,rs;
for(vector<data>::iterator it=t.begin();it!=t.end();++it){
if((*it).v<=mid){
ls.push_back(*it);
}
else{
rs.push_back(*it);
}
}
solve(ls,l,mid);
solve(rs,mid+1,r);
}
int main(){
n=read();
for(int i=1;i<=n;++i){
int x=read();
if(x)addedge(x,i);
else root=i;
}
dfs(root,0);
m=read();
for(int i=1;i<=m;++i){
int opt=read();
if(opt==1){
int x=read(),y=read(),v=read();
int lca=getlca(x,y);
if(v>=i)ans2[i]=0;
else q.push_back(data(i,opt,x,y,i-v,lca));
ans1[i]=dep[x]+dep[y]-dep[lca]-dep[st[lca][0]];
}
else{
int x=read();
q.push_back(data(i,opt,x,0,i,0));
}
}
solve(q,1,m);
for(int i=1;i<=m;++i){
if(ans1[i])printf("%d %d\n",ans1[i],ans2[i]);
}
return 0;
}