【BZOJ1146】網路管理(CTSC2008)-樹狀陣列+主席樹
阿新 • • 發佈:2018-12-15
測試地址:網路管理 做法: 本題需要用到樹狀陣列+主席樹。 經典的帶修改樹上路徑第大問題,不過我太菜了居然忘了有樹上主席樹這個東西… 不帶修改的話能用樹上主席樹做,那麼帶修改怎麼辦呢?因為一次修改會影響一棵子樹上的所有線段樹,所以我們還是把樹拍成DFS序,就變成區間修改了。注意到查詢的時候只是查單棵線段樹,因此可以運用差分的方法,把上述操作變成單點修改,字首和求和,這個就用樹狀陣列套主席樹(準確上來講算樹狀陣列套動態開點線段樹?)就可以統計修改的貢獻了(即變成單次修改/查詢棵線段樹)。注意原來點的貢獻和修改的貢獻是在不同的結構上統計的,一個是在樹上主席樹上統計,一個是在樹狀陣列套線段樹上統計。在二分的時候,把所有帶貢獻的線段樹點列出來,每次算貢獻的時候都掃一遍,向下走的時候所有點一起走即可。這樣我們就以的時間複雜度解決了這個問題。 寫起來挺複雜,但也不是太難,居然1A了,信心獲得增長。 以下是本人程式碼:
#include <bits/stdc++.h>
using namespace std;
int n,q,m,tot=0,val[100010],tote=0,first[100010]={0};
int pos[200010],k[100010],a[100010],b[100010];
int fa[100010][20]={0},dep[100010]={0},in[100010],out[100010],tim=0;
int seg[10000010]={0},ch[10000010][2]={0},rt[200010]={0};
int totp, p[510],type[510];
struct edge
{
int v,next;
}e[200010];
struct forsort
{
bool type;
int id,val;
}f[200010];
void insert(int a,int b)
{
e[++tote].v=b;
e[tote].next=first[a];
first[a]=tote;
}
void pushup(int v)
{
seg[v]=seg[ch[v][0]]+seg[ch[v][1]];
}
void insert(int &v,int last,int l,int r,int x)
{
v=++tot;
seg[v]=seg[last];
ch[v][0]=ch[last][0];
ch[v][1]=ch[last][1];
if (l==r) {seg[v]++;return;}
int mid=(l+r)>>1;
if (x<=mid) insert(ch[v][0],ch[last][0],l,mid,x);
else insert(ch[v][1],ch[last][1],mid+1,r,x);
pushup(v);
}
void modify(int &v,int l,int r,int x,int d)
{
if (!v) v=++tot;
if (l==r) {seg[v]+=d;return;}
int mid=(l+r)>>1;
if (x<=mid) modify(ch[v][0],l,mid,x,d);
else modify(ch[v][1],mid+1,r,x,d);
pushup(v);
}
void dfs(int v)
{
in[v]=++tim;
insert(rt[v],rt[fa[v][0]],1,m,val[v]);
for(int i=first[v];i;i=e[i].next)
if (e[i].v!=fa[v][0])
{
fa[e[i].v][0]=v;
dep[e[i].v]=dep[v]+1;
dfs(e[i].v);
}
out[v]=tim;
}
int lowbit(int x)
{
return x&(-x);
}
void Add(int v,int x,int d)
{
for(int i=v;i<=n;i+=lowbit(i))
modify(rt[n+i],1,m,x,d);
}
void insert_p(int v,int d)
{
if (!v) return;
p[++totp]=v,type[totp]=d;
}
void Sum(int v,int d)
{
for(int i=v;i;i-=lowbit(i))
insert_p(rt[n+i],d);
}
void query(int k)
{
int l=1,r=m,s,mid;
while(l!=r)
{
s=0,mid=(l+r)>>1;
for(int i=1;i<=totp;i++)
s+=seg[ch[p[i]][1]]*type[i];
if (s<k)
{
r=mid;
for(int i=1;i<=totp;i++)
p[i]=ch[p[i]][0];
k-=s;
}
else
{
l=mid+1;
for(int i=1;i<=totp;i++)
p[i]=ch[p[i]][1];
}
}
s=0;
for(int i=1;i<=totp;i++)
s+=seg[p[i]]*type[i];
if (s<k) printf("invalid request!\n");
else printf("%d\n",pos[l]);
}
bool cmp(forsort a,forsort b)
{
return a.val<b.val;
}
int lca(int a,int b)
{
if (dep[a]<dep[b]) swap(a,b);
for(int i=18;i>=0;i--)
if (dep[fa[a][i]]>=dep[b])
a=fa[a][i];
if (a==b) return a;
for(int i=18;i>=0;i--)
if (fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[++tot].val);
f[tot].type=0,f[tot].id=i;
}
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b),insert(b,a);
}
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&k[i],&a[i],&b[i]);
if (!k[i])
{
f[++tot].type=1,f[tot].id=i;
f[tot].val=b[i];
}
}
sort(f+1,f+tot+1,cmp);
m=0;
for(int i=1;i<=tot;i++)
{
if (i==1||f[i].val!=f[i-1].val) pos[++m]=f[i].val;
if (f[i].type) b[f[i].id]=m;
else val[f[i].id]=m;
}
tot=0;
dep[1]=1;
dfs(1);
for(int i=1;i<=18;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
for(int i=1;i<=q;i++)
{
if (!k[i])
{
Add(in[a[i]],val[a[i]],-1);
Add(out[a[i]]+1,val[a[i]],1);
val[a[i]]=b[i];
Add(in[a[i]],val[a[i]],1);
Add(out[a[i]]+1,val[a[i]],-1);
}
else
{
totp=0;
insert_p(rt[a[i]],1);
insert_p(rt[b[i]],1);
int g=lca(a[i],b[i]);
insert_p(rt[g],-1);
if (fa[g][0]) insert_p(rt[fa[g][0]],-1);
Sum(in[a[i]],1),Sum(in[b[i]],1),Sum(in[g],-1);
if (fa[g][0]) Sum(in[fa[g][0]],-1);
query(k[i]);
}
}
return 0;
}