bzoj 4012 [HNOI2015]开店 树链剖分+可持久化线段树

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/88962385

Description


给一棵树,Q次询问颜色在[L,R]之间的点到x的距离之和,强制在线
n 1.5 × 1 0 5 , Q 2 × 1 0 5 n\le1.5\times10^5,Q\le2\times10^5

Solution


带修改的话就是树套树,这里不用修改就可持久化就好了

说一下这里标记永久化的做法吧
对于一个修改区间[l,r],如果它完全包含了当前线段区间[tl,tr],那么我们就把标记打在这个位置
如果[tl,tr]完全包含了[l,r],那么我们就把[l,r]的贡献加在这个位置的区间和里面

然后就没了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) (x&-x)
#define fi first
#define se second

typedef long long LL;
typedef std:: pair <int,LL> pair;
const int N=200005;

struct edge {int y,w,next;} e[N*2];

struct treeNode {int l,r,tag; LL sum;} t[N*205];

pair p[N],s[N];

int dis[N],ls[N],rt[N],a[N],b[N],edCnt,tot;
int size[N],pos[N],fa[N],bl[N];

LL sum[N];

pair operator +(pair a,pair b) {
	return pair(a.fi+b.fi,a.se+b.se);
}

pair operator -(pair a,pair b) {
	return pair(a.fi-b.fi,a.se-b.se);
}

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void add_edge(int x,int y,int w) {
	e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {x,w,ls[y]}; ls[y]=edCnt;
}

void modify(int &now,int pre,int tl,int tr,int l,int r) {
	t[now=++tot]=t[pre];
	if (tl>=l&&tr<=r) return (void) (t[now].tag++);
	t[now].sum+=sum[r]-sum[l-1];
	int mid=(tl+tr)>>1;
	if (r<=mid) modify(t[now].l,t[pre].l,tl,mid,l,r);
	else if (l>mid) modify(t[now].r,t[pre].r,mid+1,tr,l,r);
	else {
		modify(t[now].l,t[pre].l,tl,mid,l,mid);
		modify(t[now].r,t[pre].r,mid+1,tr,mid+1,r);
	}
}

LL query(int now,int tl,int tr,int l,int r) {
	LL res=t[now].tag*(sum[r]-sum[l-1]);
	if (tl>=l&&tr<=r) return res+t[now].sum;
	int mid=(tl+tr)>>1;
	if (r<=mid) res+=query(t[now].l,tl,mid,l,r);
	else if (l>mid) res+=query(t[now].r,mid+1,tr,l,r);
	else res+=query(t[now].l,tl,mid,l,mid)+query(t[now].r,mid+1,tr,mid+1,r);
	return res;
}

void change(int x,int p) {
	for (;x;x=fa[bl[x]]) {
		modify(rt[p],rt[p],1,pos[0],pos[bl[x]],pos[x]);
	}
}

LL ask(int x,int p) {
	LL res=0;
	for (;x;x=fa[bl[x]]) {
		res+=query(rt[p],1,pos[0],pos[bl[x]],pos[x]);
	}
	return res;
}

void dfs1(int x) {
	size[x]=1;
	for (int i=ls[x];i;i=e[i].next) {
		if (e[i].y==fa[x]) continue;
		dis[e[i].y]=dis[x]+e[i].w; fa[e[i].y]=x;
		dfs1(e[i].y); size[x]+=size[e[i].y];
	}
}

void dfs2(int x,int up,int d) {
	int mx=0,w; pos[x]=++pos[0];
	sum[pos[x]]=sum[pos[x]-1]+d; bl[x]=up;
	for (int i=ls[x];i;i=e[i].next) {
		if (e[i].y!=fa[x]&&size[e[i].y]>size[mx]) mx=e[i].y,w=e[i].w;
	}
	if (!mx) return ;
	dfs2(mx,up,w);
	for (int i=ls[x];i;i=e[i].next) {
		if (e[i].y!=fa[x]&&e[i].y!=mx) dfs2(e[i].y,e[i].y,e[i].w);
	}
}

void add(int x,int v) {
	for (;x<=pos[0];x+=lowbit(x)) s[x].fi++,s[x].se+=v;
}

pair get(int x) {
	pair res=pair(0,0);
	for (;x;x-=lowbit(x)) res=res+s[x];
	return res;
}

int main(void) {
	freopen("data.in","r",stdin);
	int n=read(),Q=read(),A=read();
	rep(i,1,n) a[i]=b[i]=read();
	std:: sort(b+1,b+n+1);
	int size=std:: unique(b+1,b+n+1)-b-1;
	rep(i,1,n) {
		a[i]=std:: lower_bound(b+1,b+size+1,a[i])-b;
		p[i]=pair(a[i],i);
	}
	std:: sort(p+1,p+n+1);
	rep(i,2,n) {
		int x=read(),y=read(),w=read();
		add_edge(x,y,w);
	}
	dfs1(1); dfs2(1,1,0);
	rep(i,1,n) {
		int x=p[i].se;
		if (p[i-1].fi!=p[i].fi) rt[a[x]]=rt[p[i-1].fi];
		change(x,p[i].fi);
		add(p[i].fi,dis[x]);
	}
	LL lastans=0;
	for (int x,l,r;Q--;) {
		x=read(),l=read(),r=read();
		l=(l+lastans)%A,r=(r+lastans)%A;
		if (r<l) std:: swap(l,r);
		r=std:: upper_bound(b+1,b+size+1,r)-b-1;
		l=std:: upper_bound(b+1,b+size+1,l-1)-b-1;
		pair tmp=get(r)-get(l);
		LL res=1LL*dis[x]*tmp.fi+tmp.se;
		LL wjp=ask(x,r)-ask(x,l);
		printf("%lld\n", lastans=res-2*wjp);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/88962385