zoukankan      html  css  js  c++  java
  • Codeforces Round #703 (Div. 2)

    C. Guessing the Greatest

    题目描述

    点此看题

    解法

    一开始只想到了傻逼二分,需要 (40) 次。

    我们可以先找到全局的次大值的位置 (p),问一次就可以知道最大值在他的哪一边。假设最大值在右边,那么问 ([p,r]) 的返回值如果是 (p) 就可知最大值在此区间内,利用可以性质可以 (20) 次以内倍增出答案。

    那么为什么一开始的思路不行,因为没有全局的思维

    F. Pairs of Paths

    题目描述

    点此看题

    给定 (n) 个点的树,(m) 条简单路径,求有且仅有一个公共点的路径对数。

    (1leq n,mleq 300000)

    解法

    好题,如果你不好好讨论的话很容易头就昏了。

    首先考虑相交的两个路径是什么样子,手玩发现有这两种情况(嫖的图):

    image.png

    把这两种情况统一起来很麻烦,还不如分开处理呢!第一种情况就是两条路径拥有共同的 ( t lca),第二种情况就是两条路径相交于某一条路径的 ( t lca)他们的共性是交点一定是某个 ( t lca),要留心这一点。

    考虑下第一种情况怎么做,发现唯一的限制是四个点来自不同的子树,那么自然的想到可以求出子树的根来看是否来自不同子树。对于每一条路径都定义一个三元组 ((lca,a,b)),其中 (a,b) 分别表示两个端点的树根,如果端点是 ( t lca) 那么我们重新给个编号(因为这时候要判定为不同),为了方便我们通过 ( t swap) 是的 (a<b)

    现在的问题变成了求有多少对三元组满足 ( t lca) 相同且 (a_1,b_1,a_2,b_2(a_1<b_1,a_2<b_2)) 互不相同,那么我们可以先把三元组按 ( t lca) 排序,然后按 (a) 严格递减排序(每次处理若干相同的 (a)),就能保证 (a) 互不相同。然后我们开个桶 (bt),设访问过得三元组有 (cnt) 对,那么把 (ans-bt[b]) 计入答案,算完之后把 (bt[a],bt[b])(1),因为 (a_i) 是递减的所以 (b_i) 和以前的 (a) 可以判重。

    考虑第二种情况怎么做,交点是某个 ( t lca),并且另一个 ( t lca) 一定是它的祖先,所以可以把三元组按 ( t lca) 的深度排序,然后我们就是要找以前出现过的 (B_1),可以把 ( t lca) 的两个端点 (B_1,B_2)(这里的含义如图)加入树状数组中,算答案的时候就看 ( t lca_i) 的子树内的端点数量即可,注意要减去 (a_i,b_i) 子树内的端点个数。

    时间复杂度 (O(nlog n))

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int M = 300005;
    #define ll long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,tot,Ind,f[M],dep[M],fa[M][20];
    int b[2*M],bit[M],l[M],r[M];ll ans;
    struct edge
    {
    	int v,next;
    }e[2*M];
    struct node
    {
    	int x,y,a,b,lca;
    	bool operator < (const node &r) const
    	{
    		if(dep[lca]!=dep[r.lca]) return dep[lca]<dep[r.lca];
    		if(lca!=r.lca) return lca<r.lca;
    		return a>r.a;
    	}
    }s[M];
    void dfs(int u)
    {
    	l[u]=++Ind;
    	dep[u]=dep[fa[u][0]]+1;
    	for(int i=1;i<20;i++)
    		fa[u][i]=fa[fa[u][i-1]][i-1];
    	for(int i=f[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u][0]) continue;
    		fa[v][0]=u;dfs(v); 
    	}
    	r[u]=Ind;
    }
    int lca(int u,int v)
    {
    	if(dep[u]<=dep[v]) swap(u,v);
    	for(int i=19;i>=0;i--)
    		if(dep[fa[u][i]]>=dep[v])
    			u=fa[u][i];
    	if(u==v) return u;
    	for(int i=19;i>=0;i--)
    		if(fa[u][i]^fa[v][i])
    			u=fa[u][i],v=fa[v][i];
    	return fa[u][0];
    }
    int jump(int u,int x)
    {
    	if(u==x) return ++k;
    	for(int i=19;i>=0;i--)
    		if(dep[fa[u][i]]>dep[x])
    			u=fa[u][i];
    	return u;
    }
    int lowbit(int x)
    {
    	return x&(-x);
    }
    void add(int x)
    {
    	for(int i=x;i<=n;i+=lowbit(i))
    		bit[i]++;
    }
    int ask(int x)
    {
    	int res=0;
    	for(int i=x;i>=1;i-=lowbit(i))
    		res+=bit[i];
    	return res;
    }
    signed main()
    {
    	n=k=read();
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		e[++tot]=edge{v,f[u]},f[u]=tot;
    		e[++tot]=edge{u,f[v]},f[v]=tot;
    	}
    	dfs(1);
    	m=read();
    	for(int i=1;i<=m;i++)
    	{
    		s[i].x=read();s[i].y=read();
    		s[i].lca=lca(s[i].x,s[i].y);
    		s[i].a=jump(s[i].x,s[i].lca);
    		s[i].b=jump(s[i].y,s[i].lca);
    		if(s[i].a>s[i].b)
    		{
    			swap(s[i].x,s[i].y);
    			swap(s[i].a,s[i].b);
    		}
    	}
    	sort(s+1,s+1+m);
    	for(int i=1,j=1;i<=m;i++)
    	{
    		j=i;
    		for(;s[i].lca==s[j+1].lca;j++);
    		int cnt=0;
    		for(int k=i;k<=j;k++)
    		{
    			int k2=k;
    			while(k2<j && s[k].a==s[k2+1].a) k2++;
    			for(int p=k;p<=k2;p++)
    				ans+=cnt-b[s[p].b];
    			for(int p=k;p<=k2;p++)
    				b[s[p].a]++,b[s[p].b]++;
    			cnt+=k2-k+1;k=k2;
    		}
    		for(int k=i;k<=j;k++)
    			b[s[k].a]=b[s[k].b]=0;
    		for(int k=i;k<=j;k++)
    		{
    			ans+=ask(r[s[k].lca])-ask(l[s[k].lca]-1);
    			if(s[k].a<=n) ans-=ask(r[s[k].a])-ask(l[s[k].a]-1);
    			if(s[k].b<=n) ans-=ask(r[s[k].b])-ask(l[s[k].b]-1);
    		}
    		for(int k=i;k<=j;k++)
    			add(l[s[k].x]),add(l[s[k].y]);
    		i=j;
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    单例模式
    spring boot 调度任务
    linux yum安装MySQL5.6
    day5模块学习--sys模块
    day5模块学习 -- os模块学习
    day5模块学习--random模块
    day5模块学习 -- time、datetime时间模块
    生成随机验证码的方法
    SQL中format()函数对应的格式
    day4作业小代码练习
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14766230.html
Copyright © 2011-2022 走看看