• bzoj4012:[HNOI2015]开店


    传送门

    一开始想着二维线段树+二次换根来着,然而空间不够并且强制在线
    然后就想到了一个比较好的计算方式,详见bzoj3626[LNOI2014]LCA
    就是类似这个统计距离和的方法,不过这次是有边权的,区间修改的话,预处理路径的长度就好了
    然后发现还是不好做,看题解去
    然后看到了动态点分治(本人过弱,听懂了就是不会写代码,就一直搁着)
    还好有拿那个思路写的,先树链剖分用颗主席树维护就好了,才发现可以将年龄那一维用主席树前缀和处理掉
    但是空间依然很紧,用一下标记永久化(太久没写标记永久化了,写了好久才写对)
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=2e5+10;
    long long ss[maxn],dis[maxn],sum[maxn*30],lastans,s[maxn];
    int pre[maxn*2],nxt[maxn*2],h[maxn],v[maxn*2],cnt,tot,f[maxn],ans;
    int n,m,A,dep[maxn],size[maxn],w[maxn],top[maxn],id[maxn],tmp;
    int rt[maxn],ls[maxn*30],rs[maxn*30],tag[maxn*30];
    struct oo{int x,id;}a[maxn];
    bool cmp(oo a,oo b){return a.x<b.x;}
    void add(int x,int y,int z)
    {
    	pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z;
    	pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=z;
    }
    void dfs(int x,int fa)
    {
    	size[x]=1,f[x]=fa;
    	for(rg int i=h[x];i;i=nxt[i])
    		if(pre[i]!=fa)dep[pre[i]]=dep[x]+1,dis[pre[i]]=dis[x]+v[i],dfs(pre[i],x),size[x]+=size[pre[i]];
    }
    void dfs1(int x,int ff)
    {
    	top[x]=ff,id[x]=++tmp;ss[tmp]=dis[x]-dis[f[x]];int k=0;
    	for(rg int i=h[x];i;i=nxt[i])
    		if(dep[pre[i]]>dep[x]&&size[pre[i]]>size[k])k=pre[i];
    	if(!k)return ;dfs1(k,ff);
    	for(rg int i=h[x];i;i=nxt[i])
    		if(dep[pre[i]]>dep[x]&&pre[i]!=k)dfs1(pre[i],pre[i]);
    }
    void change(int x,int &k,int l,int r,int a,int b,int id)
    {
    	k=++tot,ls[k]=ls[x],rs[k]=rs[x],tag[k]=tag[x],sum[k]=sum[x];
    	if(a<=l&&b>=r){tag[k]++;return ;}
    	int mid=(l+r)>>1;sum[k]+=ss[min(r,b)]-ss[max(l,a)-1];
    	if(a<=mid)change(ls[x],ls[k],l,mid,a,b,id);
    	if(b>mid)change(rs[x],rs[k],mid+1,r,a,b,id);
    }
    void modify(int k,int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		change(rt[k],rt[k],1,n,id[top[x]],id[x],k);
    		x=f[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	change(rt[k],rt[k],1,n,id[x],id[y],k);
    }
    long long get(int x,int &k,int l,int r,int a,int b,int now)
    {
    	long long ans=0,mid=(l+r)>>1;
    	if(a<=l&&b>=r)return (now+tag[k]-tag[x])*(ss[r]-ss[l-1])+sum[k]-sum[x];
    	if(a<=mid)ans+=get(ls[x],ls[k],l,mid,a,b,now+tag[k]-tag[x]);
    	if(b>mid)ans+=get(rs[x],rs[k],mid+1,r,a,b,now+tag[k]-tag[x]);
    	return ans;
    }
    long long qsum(int a,int b,int x,int y)
    {
    	long long ans=0;
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		ans+=get(rt[a],rt[b],1,n,id[top[x]],id[x],0);
    		x=f[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	ans+=get(rt[a],rt[b],1,n,id[x],id[y],0);
    	return ans;
    }
    signed main()
    {
    	read(n),read(m),read(A);
    	for(rg int i=1;i<=n;i++)read(a[i].x),a[i].id=i,w[i]=a[i].x;
    	for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),read(z),add(x,y,z);
    	dfs(1,0),dfs1(1,1),sort(a+1,a+n+1,cmp),sort(w+1,w+n+1);
    	for(rg int i=1;i<=n;i++)ss[i]+=ss[i-1];
    	for(rg int i=1;i<=n;i++)
    	{
    		rt[i]=rt[i-1],s[i]=s[i-1]+dis[a[i].id];
    		modify(i,1,a[i].id);
    	}
    	for(rg int i=1,u,a,b,l,r,x,y;i<=m;i++)
    	{
    		read(u),read(x),read(y);
    		a=min((x+lastans)%A,(y+lastans)%A),b=max((x+lastans)%A,(y+lastans)%A);
    		l=lower_bound(w+1,w+n+1,a)-w;
    		r=lower_bound(w+1,w+n+1,b+1)-w;r--;
    		lastans=dis[u]*(r-l+1)+s[r]-s[l-1]-2*qsum(l-1,r,1,u);
    		printf("%lld
    ",lastans);
    	}
    }
    
  • 相关阅读:
    Firemonkey绑定对象列表
    Firemonkey 自定义Button的Style
    Delphi中使用GDI+进行绘图(2)
    Delphi中使用GDI+进行绘图(1)
    很好用的一个类:TJvAppXMLFileStorage
    我的Win32开发抉择,Delphi老将复出
    实现动态的XML文件读写操作
    一个简单的统计图像主颜色的算法(C#源代码)
    开始使用THREE.JS
    C++应用程序在Windows下的编译、链接(一)概述
  • 原文地址:https://www.cnblogs.com/lcxer/p/10574062.html
Copyright © 2020-2023  润新知