• 【bzoj4940】这是我自己的发明


    Portal --> bzoj4940

    Solution

      (原题这题面到底是。。怎么回事啊深深的套路qwq)

      感觉自己对根号的算法还是很。。没有感觉啊==

      实际上这题和bzoj5016没有任何区别的感觉。。。那个换根操作不过是一个幌子而已,处理出(dfn)序之后根据当前根(rt)(dfn)序和(x)的子树范围的关系可以直接将查询变成(dfn)序上的至多两段区间

      然后就变成了和bzoj5016一模一样的东西。。只是区间可能有两个这样的话直接两两组合一下什么的就好了

    ​  具体的话还是写一下:其实我们需要处理的是这样一个式子

    [sumlimits_{x}cnt_x(l_1,r_1)cdot cnt_x(l_2,r_2) ]

      然后我们来快乐处理式子

    [egin{aligned} &sumlimits_{x}cnt_x(l_1,r_1)cdot cnt_x(l_2,r_2)\ =&sumlimits_{x}(cnt_x(1,r_1)-cnt_x(1,l_1-1))cdot (cnt_x(1,r_2)-cnt_x(1,l_2-1))\ =&sumlimits_{x}cnt_x(1,r_1)cdot cnt_x(1,r_2)-sumlimits_{x}cnt_x(1,r_1)cdot cnt_x(1,l_2-1)-sumlimits_{x}cnt_x(1,l_1-1)cdot cnt_x(1,r_2)+sumlimits_{x}cnt_x(1,l_1-1)cdot cnt_x(1,l_2-1) end{aligned} ]

      然后我们记(Q(l,r)=sumlimits_{x}cnt_x(1,l)cdot cnt_x(1,r)),那么也就是说我们要求的是

    [sumlimits_{x}Q(r_1,r_2)-Q(r_1,l_2-1)-Q(l_1-1,r_2)+Q(l_1-1,l_2-1) ]

      然后对于(Q(l,r))我们可以用莫队处理

      对于每一个值(离散化之后就至多只有(n)个了)记一个(cnt)表示当前区间中的数量,具体一点的话就是假设当前的左右指针分别为(l)(r)(cntl[x])记录([1,l])区间内(x)这个值得数量,(cntr[x])记录([1,r])区间内(x)这个值的数量,然后再用(nowval)记录一下当前的答案,每次移动的时候加上(或者减去)对应的贡献就好了(具体的话其实还是加上(cntl[val[r]])或者(cntr[val[l]]),反正就是。。上面乘法中的其中一个(-1)了然后拆一下括号什么的就很清楚了)

      那么这样的话,对于原问题中的每组询问我们应该会得到。。至多。。(9)(Q(l,r))这样的询问,所以直接莫队爆搞一波就好了

      复杂度的话。。emmm虽然说算出来很大但是。。可以过嗯qwq

      

    ​  mark:场上真的。。实在不行就想一想根号的做法吧qwq并不是说什么题都要log的啊对不对qwq根号说不定就过了呢==

      
      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define Pr pair<int,int>
    #define mp make_pair
    using namespace std;
    const int N=100010,M=500010,TOP=20;
    struct xxx{
    	int y,nxt;
    }a[N*2];
    int num[N];
    struct Q{
    	int l,r,id,val;
    	Q(){}
    	Q(int l1,int r1,int id1,int val1){l=l1; r=r1; id=id1; val=val1;}
    	friend bool operator < (Q x,Q y){return num[x.l]==num[y.l]?x.r<y.r:num[x.l]<num[y.l];}
    }q[M*10];
    Pr rec1[10],rec2[10];
    int f[N][TOP+1],dep[N],mxdfn[N];
    int h[N],val[N],lis[N],st[N],ed[N];
    ll ans[M],cntl[N],cntr[N];
    int n,m,sq,cntq,dfn_t,rt,tot,cntQ;
    void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
    void solve(){
    	sort(q+1,q+1+cntq);
    	int nowl=0,nowr=0;
    	ll nowval=0;
    	for (int i=1;i<=cntq;++i){
    		while (nowl<q[i].l)
    			nowval+=cntr[val[lis[++nowl]]],++cntl[val[lis[nowl]]];
    		while (nowr<q[i].r)
    			nowval+=cntl[val[lis[++nowr]]],++cntr[val[lis[nowr]]];
    		while (nowl>q[i].l)
    			nowval-=cntr[val[lis[nowl]]],--cntl[val[lis[nowl--]]];
    		while (nowr>q[i].r)
    			nowval-=cntl[val[lis[nowr]]],--cntr[val[lis[nowr--]]];
    		ans[q[i].id]+=nowval*q[i].val;
    	}
    }
    void prework(){
    	lis[0]=n;
    	sort(lis+1,lis+1+lis[0]);
    	lis[0]=unique(lis+1,lis+1+lis[0])-lis-1;
    	for (int i=1;i<=n;++i)
    		val[i]=lower_bound(lis+1,lis+1+lis[0],val[i])-lis;
    }
    void dfs(int fa,int x,int d){
    	int u;
    	st[x]=++dfn_t; lis[dfn_t]=x; dep[x]=d; mxdfn[x]=dfn_t;
    	f[x][0]=fa;
    	for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=h[x];i!=-1;i=a[i].nxt){
    		u=a[i].y;
    		if (u==fa) continue;
    		dfs(x,u,d+1);
    		mxdfn[x]=max(mxdfn[x],mxdfn[u]);
    	}
    	ed[x]=dfn_t;
    }
    int jump(int x,int d){
    	if (!d) return x;
    	for (int i=0;i<=TOP;++i)
    		if (d>>i&1)
    			x=f[x][i];
    	return x;
    }
    void get_seg(int x,Pr *rec,int &cnt){
    	int pre;
    	cnt=0;
    	if (rt==x){
    		rec[++cnt]=mp(1,n);
    	}
    	else if (st[rt]<st[x]||st[rt]>ed[x]){
    		rec[++cnt]=mp(st[x],ed[x]);
    	}
    	else{
    		pre=jump(rt,dep[rt]-dep[x]-1);
    		if (st[pre]>1) rec[++cnt]=mp(1,st[pre]-1);
    		if (mxdfn[pre]<n) rec[++cnt]=mp(mxdfn[pre]+1,n);
    	}
    }
    void add_q(int l1,int r1,int l2,int r2,int id){
    	q[++cntq]=Q(r1,r2,id,1);
    	if (l2-1)
    		q[++cntq]=Q(r1,l2-1,id,-1);
    	if (l1-1)
    		q[++cntq]=Q(l1-1,r2,id,-1);
    	if (l2-1&&l1-1)
    		q[++cntq]=Q(l1-1,l2-1,id,1);
    }
    void div(int x,int y,int id){
    	int cnt1,cnt2,l1,r1,l2,r2;
    	get_seg(x,rec1,cnt1);
    	get_seg(y,rec2,cnt2);
    	for (int i=1;i<=cnt1;++i)
    		for (int j=1;j<=cnt2;++j)
    			add_q(rec1[i].first,rec1[i].second,rec2[j].first,rec2[j].second,id);
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y,op;
    	scanf("%d%d",&n,&m);
    	sq=sqrt(n);
    	for (int i=1;i<=n;++i) scanf("%d",val+i),num[i]=(i-1)/sq,lis[i]=val[i];
    	prework();
    	memset(h,-1,sizeof(h));
    	tot=0;
    	for (int i=1;i<n;++i){
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x);
    	}
    	dfn_t=0; lis[0]=0;
    	dfs(0,1,1);
    	rt=1;
    	cntq=0; cntQ=0;
    	for (int i=1;i<=m;++i){
    		scanf("%d",&op);
    		if (op==1){
    			scanf("%d",&rt);
    		}
    		else{
    			scanf("%d%d",&x,&y);
    			div(x,y,++cntQ);
    		}
    	}
    	solve();
    	for (int i=1;i<=cntQ;++i) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    PHP数组的几个操作,求并集,交集,差集,数组与字符串的相互转换及数组去重
    文件系统添加链接
    HTML中插入视频
    magento模块的建立
    数组函数
    字符串函数
    阿里服务器用户的添加
    ViewChild
    GitHub 图片加载不出来怎么办
    常用正则表达式
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9799931.html
Copyright © 2020-2023  润新知