【GDOI2014模擬】雨天的尾巴
阿新 • • 發佈:2018-05-12
lca 打出 房子 include 動態 合並操作 return why 以及
其實不然(我1.5h把熟練剖分打出來,以為能過50%。結果打錯了,20%。然後。。。打暴力的人都是50%,#%……&*)。
我們註意到z<=10^9,那麽的數據範圍。
但是m<=100000,所以就先做個離散化。
。。。
接著用到個很神奇的東西,叫線段樹合並。
對於樹上的每一個節點開一棵線段樹,記錄該節點的每個z的數量以及某一段z的最大值。註意要動態開節點,否則會爆空間。
發現,如果要修改從x到y的路徑,其實就是將x的z值加一,y的z值加一,lca(x,y)的z值減一以及fa[lca(x,y)]的z值減一(why?因為當線段樹合並後從x到lca(x,y)的路徑上和從y到lca(x,y)的路徑上的每個節點的z值都加一,但 lca(x,y)這個節點重復加了,那麽就減掉。不過剩余的z值還會繼續上傳,所以在fa[lca(x,y)]**就把上傳的z值減去)
合並操作
題目
深繪裏一直很討厭雨天。
灼熱的天氣穿透了前半個夏天,後來一場大雨和隨之而來的洪水,澆滅了一切。
雖然深繪裏家鄉的小村落對洪水有著頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連
根拔起,以及田地裏的糧食被弄得一片狼藉。
無奈的深繪裏和村民們只好等待救濟糧來維生。
不過救濟糧的發放方式很特別。
首先村落裏的一共有n 座房屋,並形成一個樹狀結構。然後救濟糧分m 次發放,每次選擇
兩個房屋(x,y),然後對於x 到y 的路徑上(含x 和y) 每座房子裏發放一袋z 類型的救濟糧。
然後深繪裏想知道,當所有的救濟糧發放完畢後,每座房子裏存放的最多的是哪種救濟糧。
分析
相信大多數人都跟我一樣,看到這道題,果斷認為是樹鏈剖分。
我們註意到z<=10^9,那麽的數據範圍。
但是m<=100000,所以就先做個離散化。
。。。
接著用到個很神奇的東西,叫線段樹合並。
對於樹上的每一個節點開一棵線段樹,記錄該節點的每個z的數量以及某一段z的最大值。註意要動態開節點,否則會爆空間。
發現,如果要修改從x到y的路徑,其實就是將x的z值加一,y的z值加一,lca(x,y)的z值減一以及fa[lca(x,y)]的z值減一(why?因為當線段樹合並後從x到lca(x,y)的路徑上和從y到lca(x,y)的路徑上的每個節點的z值都加一,但
合並操作
int mesh(int x,int y,int l,int r) { if(l==r) { tree[x].v+=tree[y].v; return 0; } int mid=(l+r)/2; if(tree[y].l) { if(!tree[x].l) tree[x].l=tree[y].l; else mesh(tree[x].l,tree[y].l,l,mid); } if(tree[y].r) { if(!tree[x].r) tree[x].r=tree[y].r; else mesh(tree[x].r,tree[y].r,mid+1,r); } tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v); }
當然,當所有的修改操作做完後才線段樹合並,否則會超時。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
using namespace std;
struct trees
{
int l,r,v;
}tree[8000000];
struct read
{
int x,y,z;
}re[110000];
int next[201000],last[201000],to[201000],po,tot,n,m,g[200000][20],t[200000],deep[200000],f[200000],sum,ans[2000000];
bool cmp(read x,read y)
{
return x.z<y.z;
}
int bj(int x,int y)
{
next[++tot]=last[x];
last[x]=tot;
to[tot]=y;
}
int dg(int x)
{
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=g[x][0])
{
deep[j]=deep[x]+1;
g[j][0]=x;
dg(j);
}
}
}
int prelca()
{
for(int j=1;j<=log2(n);j++)
{
for(int i=1;i<=n;i++)
{
g[i][j]=g[g[i][j-1]][j-1];
}
}
}
int lca(int x,int y)
{
if(deep[x]>deep[y])
{
x=x^y;
y=x^y;
x=x^y;
}
for(int i=log2(n);i>=0;i--)
{
if(deep[g[y][i]]>deep[x])
y=g[y][i];
}
if(deep[y]!=deep[x]) y=g[y][0];
for(int i=log2(n);i>=0;i--)
{
if(g[y][i]!=g[x][i])
{
y=g[y][i];
x=g[x][i];
}
}
if(x!=y) y=g[y][0];
return y;
}
int put(int v,int l,int r,int x,int y)
{
if(l==r)
{
tree[v].v+=y;
return 0;
}
int mid=(l+r)/2;
if(x<=mid)
{
if(!tree[v].l)
tree[v].l=++sum;
put(tree[v].l,l,mid,x,y);
}
else
{
if(!tree[v].r)
tree[v].r=++sum;
put(tree[v].r,mid+1,r,x,y);
}
tree[v].v=max(tree[tree[v].l].v,tree[tree[v].r].v);
}
int work(int x,int y,int z)
{
int lc=lca(x,y);
if(!f[x])
{
f[x]=++sum;
}
put(f[x],1,tot,z,1);
if(!f[y])
{
f[y]=++sum;
}
put(f[y],1,tot,z,1);
if(!f[lc])
{
f[lc]=++sum;
}
put(f[lc],1,tot,z,-1);
if(g[lc][0])
{
if(!f[g[lc][0]]) f[g[lc][0]]=++sum;
put(f[g[lc][0]],1,tot,z,-1);
}
}
int mesh(int x,int y,int l,int r)
{
if(l==r)
{
tree[x].v+=tree[y].v;
return 0;
}
int mid=(l+r)/2;
if(tree[y].l)
{
if(!tree[x].l)
tree[x].l=tree[y].l;
else
mesh(tree[x].l,tree[y].l,l,mid);
}
if(tree[y].r)
{
if(!tree[x].r)
tree[x].r=tree[y].r;
else
mesh(tree[x].r,tree[y].r,mid+1,r);
}
tree[x].v=max(tree[tree[x].l].v,tree[tree[x].r].v);
}
int find(int v,int l,int r)
{
if(l==r)
{
return l;
}
if(tree[tree[v].l].v==0 && tree[tree[v].r].v==0)
return 0;
int mid=(l+r)/2;
if(tree[tree[v].l].v>=tree[tree[v].r].v)
{
return find(tree[v].l,l,mid);
}
else
{
return find(tree[v].r,mid+1,r);
}
}
int merge(int x)
{
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(j!=g[x][0])
{
merge(j);
if(!f[x])
{
f[x]=++sum;
}
if(!f[j])
{
f[j]=++sum;
}
mesh(f[x],f[j],1,tot);
}
}
ans[x]=find(f[x],1,tot);
}
int main()
{
scanf("%d",&n);
scanf("%d",&m);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bj(x,y);
bj(y,x);
}
deep[1]=1;
dg(1);
prelca();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&re[i].x,&re[i].y,&re[i].z);
}
sort(re+1,re+m+1,cmp);
tot=0;
sum=0;
for(int i=1;i<=m;i++)
{
if(re[i].z==t[tot])
{
re[i].z=tot;
}
else
{
t[++tot]=re[i].z;
re[i].z=tot;
}
}
for(int i=1;i<=m;i++)
{
work(re[i].x,re[i].y,re[i].z);
}
merge(1);
for(int i=1;i<=n;i++)
{
if(!f[i])
{
f[i]=++sum;
}
printf("%d\n",t[ans[i]]);
}
}
【GDOI2014模擬】雨天的尾巴