• 【XSY1642】Another Boring Problem 树上莫队


    题目大意

      给你一棵(n)个点的树,每个点有一个颜色(c_i),每次给你(x,y,k),求从(x)(y)的路径上出现次数第(k)多的颜色的出现次数

      (n,qleq 100000)

    题解

      树上莫队

      先求出这棵树的dfs序(括号序列),记录每个点第一次出现的位置(st_x)和最后一次出现的位置(ed_x)

      

      若每次询问的(x,y)中有一个是另一个的祖先(设(x)(y)的祖先),那么就可以视为询问区间([st_x,st_y])

      可是一些不在这条链上的点会出现两次,我们把出现两次的点视为没出现过。

      

      否则就视为询问([ed_x,st_y])(设(st_x<st_y))。但是(lca)处没有被统计到。直接暴力把(lca)处的贡献统计一下就可以了。

      

      其他的和普通莫队一样了。

      时间复杂度:(O((n+q)sqrt{n}))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<list>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    list<int> l[200010];
    int f[200010][20];
    int st[500010];
    int ed[500010];
    int ti;
    int w[1000010];
    int c[500010];
    int a[500010];
    int e[500010];
    int d[500010];
    int m;
    void dfs(int x,int fa,int dep)
    {
    	st[x]=++ti;
    	w[ti]=x;
    	d[x]=dep;
    	f[x][0]=fa;
    	int i;
    	for(i=1;i<=19;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for(auto v:l[x])
    		if(v!=fa)
    			dfs(v,x,dep+1);
    	ed[x]=++ti;
    	w[ti]=x;
    }
    int getlca(int x,int y)
    {
    	if(d[x]<d[y])
    		swap(x,y);
    	int i;
    	for(i=19;i>=0;i--)
    		if(d[f[x][i]]>=d[y])
    			x=f[x][i];
    	if(x==y)
    		return x;
    	for(i=19;i>=0;i--)
    		if(f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    int bl;
    int ans[500010];
    int a1[500010];
    int a2[500010];
    int g[500010];
    int n,q;
    struct p
    {
    	int l,r;
    	int k;
    	int id;
    	int b;
    	int c;
    	p()
    	{
    		c=b=l=r=k=id=0;
    	}
    };
    p b[500010];
    int cmp(p a,p b)
    {
    	if(a.b!=b.b)
    		return a.b<b.b;
    	return a.r<b.r;
    }
    int block[500010];
    int *c1[500010];
    int *t[500010];
    void add(int x)
    {
    	a1[x]++;
    //	x=(x+bl-1)/bl;
    //	a2[x]++;
    	(*c1[x])++;
    }
    void del(int x)
    {
    	a1[x]--;
    //	x=(x+bl-1)/bl;
    //	a2[x]--;
    	(*c1[x])--;
    }
    void change(int x)
    {
    //	int &b=g[c[x]];
    	int &b=*t[x];
    	if(a[x])
    	{
    		a[x]=0;
    //		del(b);
    		a1[b]--;
    		(*c1[b])--;
    		b--;
    //		add(b);
    		a1[b]++;
    		(*c1[b])++;
    	}
    	else
    	{
    		a[x]=1;
    //		del(b);
    		a1[b]--;
    		(*c1[b])--;
    		b++;
    //		add(b);
    		a1[b]++;
    		(*c1[b])++;
    	}
    }
    int num;
    int query(int k)
    {
    	int i,j;
    	for(i=num;i>=1;i--)
    		if(a2[i]>=k)
    		{
    			j=min(n,i*bl);
    			for(;;j--)
    				if(a1[j]>=k)
    					return j;
    				else
    					k-=a1[j];
    		}
    		else
    			k-=a2[i];
    	return 0;
    }
    void rd(int &s)
    {
    	int c;
    	while((c=getchar())<'0'||c>'9');
    	s=c-'0';
    	while((c=getchar())>='0'&&c<='9')
    		s=s*10+c-'0';
    }
    int main()
    {
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    //	scanf("%d%d",&n,&q);
    	rd(n);
    	rd(q);
    	bl=500;
    	int m=0;
    	int i;
    	for(i=1;i<=n;i++)
    	{
    //		scanf("%d",&c[i]);
    		rd(c[i]);
    		e[++m]=c[i];
    	}
    	sort(e+1,e+m+1);
    	m=unique(e+1,e+m+1)-e-1;
    	for(i=1;i<=n;i++)
    		c[i]=lower_bound(e+1,e+m+1,c[i])-e;
    	int x,y;
    	for(i=1;i<n;i++)
    	{
    //		scanf("%d%d",&x,&y);
    		rd(x);
    		rd(y);
    		l[x].push_back(y);
    		l[y].push_back(x);
    	}
    	dfs(1,0,1);
    	num=(n+bl-1)/bl;
    	for(i=0;i<=n;i++)
    	{
    		c1[i]=&a2[(i+bl-1)/bl];
    		t[i]=&g[c[i]];
    	}
    	for(i=1;i<=q;i++)
    	{
    //		scanf("%d%d%d",&x,&y,&b[i].k);
    		rd(x);
    		rd(y);
    		rd(b[i].k);
    		b[i].id=i;
    		if(st[x]<=st[y]&&ed[x]>=ed[y])
    		{
    			b[i].l=st[x];
    			b[i].r=st[y];
    			b[i].c=0;
    		}
    		else if(st[y]<=st[x]&&ed[y]>=ed[x])
    		{
    			b[i].l=st[y];
    			b[i].r=st[x];
    			b[i].c=0;
    		}
    		else
    		{
    			if(st[x]>st[y])
    				swap(x,y);
    			b[i].l=ed[x];
    			b[i].r=st[y];
    			b[i].c=1;
    		}
    		b[i].b=(b[i].l+bl-1)/bl;
    	}
    	sort(b+1,b+q+1,cmp);
    	int l=1,r=0;
    	for(i=1;i<=q;i++)
    	{
    		while(r<b[i].r)
    			change(w[++r]);
    		while(l>b[i].l)
    			change(w[--l]);
    		while(r>b[i].r)
    			change(w[r--]);
    		while(l<b[i].l)
    			change(w[l++]);
    		if(b[i].c)
    		{
    			int lca=getlca(w[b[i].l],w[b[i].r]);
    			change(lca);
    			ans[b[i].id]=query(b[i].k);
    			change(lca);
    		}
    		else
    			ans[b[i].id]=query(b[i].k);
    	}
    	for(i=1;i<=q;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Eclipse debug模式下使用16进制(Hex)查看变量值
    无线局域网中RADIUS协议原理与实现
    浏览器发送URL的编码特性
    跨域共享cookie和跨域共享session
    Nginx与Apache工作方式
    Http字段含义
    http中有关缓存相关的几个字段
    maven中用yuicompressor和closure-compiler对js、css文件进行压缩
    Mysql 忘记密码----修改Navicat的连接密码--以及--(加入安装Navicat时没设置密码)有时新建连接设置密码,连接不成功---的问题解决方法 密码忘记的解决
    RedisTemplate的各种操作(set、hash、list、string)
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511286.html
Copyright © 2020-2023  润新知