洛谷P3241 [HNOI2015]開店 [樹鏈剖分,主席樹,lca]
阿新 • • 發佈:2018-12-01
又是一道黑題,不容易啊。。。
首先,不管年齡的限制,問題即可簡化為:給定一個點,求其他所有點到當前點的距離
回想一下樹上兩點距離公式:,兩點距離等於兩點深度相加減去lca的深度乘二
點的深度可以一次O(n)的dfs解決,問題轉化為求對於一個點u,,字好小啊。。。
回想 [LNOI2014]LCA 中求這東西的套路,我們可以把每一個v到根的路徑的tag加一,那麼只需要求u到根的路徑的權值乘tag就可以了(語文不好請見諒,如果沒有看懂可以去看[LNOI2014]LCA題解)
上面那東西很明顯的一個樹鏈剖分+線段樹即可
現在把年齡的限制加上,怎麼辦呢?
看標題,還有什麼沒有用?主席樹!
現在求距離不就是有兩個限制了嗎?此時把怪獸按年齡排序,把原有的線段樹改為主席樹即可
還有一個問題:主席樹的區間修改不能像普通線段樹一樣標記下放,要搞一個叫做標記永久化的東西,卡了我好久
細節挺多的,改了一天,一定是因為我太菜了
程式碼:
#include<bits/stdc++.h> #define sz 150050 using namespace std; typedef long long ll; struct hh{int t;ll w;int nxt;}edge[sz<<1]; int head[sz],ecnt; void make_edge(int f,int t,ll w) { edge[++ecnt]=(hh){t,w,head[f]}; head[f]=ecnt; edge[++ecnt]=(hh){f,w,head[t]}; head[t]=ecnt; } #define go(x) for (register int i=head[x];i;i=edge[i].nxt) #define o edge[i].t /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ int T,top[sz],son[sz],fa[sz],size[sz],dfn[sz],dep[sz]; ll deep[sz],fr[sz],sumd[sz]; void dfs1(int x) { size[x]=1;dep[x]=dep[fa[x]]+1; go(x) if (o!=fa[x]) { fa[o]=x;fr[o]=edge[i].w;deep[o]=deep[x]+edge[i].w; dfs1(o); size[x]+=size[o]; if (size[o]>size[son[x]]) son[x]=o; } } void dfs2(int x,int tp) { top[x]=tp;dfn[x]=++T;sumd[T]=sumd[T-1]+fr[x]; if (son[x]) dfs2(son[x],tp); go(x) if (o!=son[x]&&o!=fa[x]) dfs2(o,o); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ namespace P_Seg { struct P{ll sum,tag;int ls,rs;}tr[10000010]; int cnt,root[sz]; int modify(int pre,int l,int r,int x,int y) { int k=++cnt;tr[k]=tr[pre]; if (l==x&&r==y){tr[k].tag++;return k;} tr[k].sum+=sumd[y]-sumd[x-1]; int mid=(l+r)>>1; if (x>mid) tr[k].rs=modify(tr[pre].rs,mid+1,r,x,y); else if (y<=mid) tr[k].ls=modify(tr[pre].ls,l,mid,x,y); else tr[k].ls=modify(tr[pre].ls,l,mid,x,mid),tr[k].rs=modify(tr[pre].rs,mid+1,r,mid+1,y); return k; } ll query(int k,int l,int r,int x,int y) { if (!k) return 0; ll ret=tr[k].tag*(sumd[y]-sumd[x-1]); if (x==l&&r==y) return ret+tr[k].sum; int mid=(l+r)>>1; if (x>mid) return ret+query(tr[k].rs,mid+1,r,x,y); else if (y<=mid) return ret+query(tr[k].ls,l,mid,x,y); else return ret+query(tr[k].ls,l,mid,x,mid)+query(tr[k].rs,mid+1,r,mid+1,y); } } int rt; using namespace P_Seg; int add(int x) { while (top[x]!=1) rt=modify(rt,1,T,dfn[top[x]],dfn[x]),x=fa[top[x]]; return rt=modify(rt,1,T,1,dfn[x]); } ll qsum(int x,int rt) { ll ret=0; while (top[x]!=1) ret+=query(root[rt],1,T,dfn[top[x]],dfn[x]),x=fa[top[x]]; ret+=query(root[rt],1,T,1,dfn[x]); return ret; } int n,Q,A; struct HH { int age,id; const bool operator < (const HH &x) const {return age!=x.age?age<x.age:id<x.id;} }a[sz]; int b[sz]; template<typename QAQ> inline void read(QAQ& t) { t=0; int f=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar(); t*=f; } template<typename QAQ,typename... Args> inline void read(QAQ& t,Args&... args){read(t); read(args...);} int tot; ll Deep[sz]; int work() { int i,u,x,y,z,L,R; ll lastans=0; read(n,Q,A); for (i=1;i<=n;i++) read(b[i]),a[i]=(HH){b[i],i}; sort(b+1,b+n+1);sort(a+1,a+n+1); for (i=1;i<n;i++) read(x,y,z),make_edge(x,y,z); dfs1(1);dfs2(1,1); for (i=1;i<=n;i++) Deep[i]=Deep[i-1]+deep[a[i].id]; for (i=1;i<=n;i++) root[i]=add(a[i].id); while (Q--) { read(u,x,y); L=min((x+lastans)%A,(y+lastans)%A); R=max((x+lastans)%A,(y+lastans)%A); L=lower_bound(a+1,a+n+1,(HH){L,0})-a;R=upper_bound(a+1,a+n+1,(HH){R,(int)1e9+1})-a-1; lastans=1ll*(R-L+1)*deep[u]+Deep[R]-Deep[L-1]-2ll*(qsum(u,R)-qsum(u,L-1)); printf("%lld\n",lastans); } return 0; } int HHHH=work();//皮一下 int main(){}