zoukankan      html  css  js  c++  java
  • 牛客网 小睿睿的方案 解题报告

    小睿睿的方案

    链接:

    https://ac.nowcoder.com/acm/contest/371/C

    来源:牛客网

    题目描述

    小睿睿虽然已经是人生赢家了,但当他看见学校里其他人秀恩爱时仍旧会十分不满。他的学校有(n)个教室,教室间有(n-1)条路径且任意教室互相联通,每天他和小熙熙会选择在两个不同的教室((i,j))间的简单路径上秀恩爱。学校里一共有(m)对情侣,每对情侣中的两个人分别在教室(A,B(A ot=B)),如果他们秀恩爱时经过的教室里存在任意一对情侣,这种秀恩爱的方案就是不合法的,求合法的无序点对数

    无序点对:((i,j))((j,i))视作同一对

    输入描述:

    (1)行,(2)个整数(n,m)

    (2)(n)行,每行两个整数(a,b),表示(a,b)间存在一条边

    之后(m)行,每行两个整数(a,b),表示有一对情侣分别在教室(a)和教室(b)

    输出描述:

    一行一个整数,表示答案

    说明

    对于(30\%)的数据,(n,mle 100)

    另有(20\%)的数据,(n,mle 100000)且图的形态为一条链

    对于(100\%)的数据,(n,mle 100000)

    输入数据较大,建议使用较快的读入方式


    看了前两个题,发现很水,就来写这个题,然后最后5分钟的时候写出来了,结果数组还开小了,爆的只有80分...前面两个题还没做qaq

    统计不合法的点对

    首先搞一个点分。

    然后考虑遍历一颗儿子的子树时,可能激活前面的儿子的一个子树,把这个激活放到线段树上就是区间覆盖,然后处理一个区间覆盖和区间查询1的个数,但是从点退回父亲的时候需要撤回,我没找到别的方法,只好硬肛了一个可持久化上去。

    然后还有一个细节,就是当前子树点到分治中心的路径上有一对,这个可以激活之前的全部点,相应的,之前的子树也可能包含这样的链,就差不多处理就好了。

    复杂度(O(nlog^2 n))

    (O(nlog n))正解

    这个题感觉好像是个套路,和接水果那题有点像

    就是 处理树上路径包含统计数量之类的题目可以用(dfs)搞成二维的,然后贡献搞成矩形之类的,扫描线一下。

    这个题可以对点对是祖孙关系和两个子树关系的东西讨论,然后弄成矩形覆盖的贡献,直接扫描线就可以了。


    Code:(点分)

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #define ll long long
    const int N=2e5+10;
    template <class T>
    void read(T &x)
    {
    	x=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)) x=x*10+c-'0',c=getchar();
    }
    struct node
    {
        int v,id;
        node(){}
        node(int V,int Id){v=V,id=Id;}
    };
    std::vector <node> yuu[N];
    int n,m,Id[N];ll ans;
    int head[N],to[N<<1],Next[N<<1],cnt;
    void add(int u,int v)
    {
    	to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
    }
    int tag[N*30],sum[N*30],ch[N*30][2],tot,T,root[N];
    #define ls ch[now][0]
    #define rs ch[now][1]
    #define ols ch[las][0]
    #define ors ch[las][1]
    int New()
    {
    	tag[++tot]=0,sum[tot]=0,ch[tot][0]=ch[tot][1]=0;
    	return tot;
    }
    void pushdown(int now,int L,int R)
    {
        if(L==R) return;
    	if(tag[now])
    	{
    		int Mid=L+R>>1;
    		if(!ls) ls=New();
            tag[ls]=tag[now];
            sum[ls]=Mid+1-L;
            if(!rs) rs=New();
            tag[rs]=tag[now];
            sum[rs]=R-Mid;
    	}
    }
    void change(int las,int &now,int L,int R,int l,int r)
    {
        if(l>r) return;
    	pushdown(las,L,R);
    	now=New();
    	if(l==L&&r==R)
    	{
    		tag[now]=1;
    		sum[now]=R+1-L;
    		return;
    	}
    	int Mid=L+R>>1;
    	if(r<=Mid) change(ols,ls,L,Mid,l,r),rs=ors;
    	else if(l>Mid) ls=ols,change(ors,rs,Mid+1,R,l,r);
    	else change(ols,ls,L,Mid,l,Mid),change(ors,rs,Mid+1,R,Mid+1,r);
    	sum[now]=sum[ls]+sum[rs];
    }
    int query(int now,int L,int R,int l,int r)
    {
    	if(!now) return 0;
    	if(l==L&&r==R) return sum[now];
    	pushdown(now,L,R);
    	int Mid=L+R>>1;
    	if(r<=Mid) return query(ls,L,Mid,l,r);
    	else if(l>Mid) return query(rs,Mid,R,l,r);
    	else return query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r);
    }
    int rt,si,mi,siz[N],del[N],buct[N],is[N],tim,key[N],tl;
    int dfn[N],dfsclock;
    void dfsrt(int now,int fa)
    {
    	int mx=0;siz[now]=1;
    	for(int v,i=head[now];i;i=Next[i])
    		if((v=to[i])!=fa&&!del[v])
    		{
    			dfsrt(v,now);
    			siz[now]+=siz[v];
    			mx=mx>siz[v]?mx:siz[v];
    		}
    	mx=mx>si-siz[now]?mx:si-siz[now];
    	if(mx<mi) mi=mx,rt=now;
    }
    void dfs0(int now,int fa)
    {
    	siz[now]=1;
    	dfn[now]=++dfsclock;
    	is[now]=tim;
    	for(int v,i=head[now];i;i=Next[i])
    		if((v=to[i])!=fa&&!del[v])
    		{
    			dfs0(v,now);
    			siz[now]+=siz[v];
    		}
    }
    void dfs(int now,int fa)
    {
        ++T;
        root[T]=root[T-1];
        for(int i=0;i<yuu[now].size();i++)
        {
            int v=yuu[now][i].v,id=yuu[now][i].id;
            ++buct[id];
            if(buct[id]==2)
            {
                key[++key[0]]=now;
                change(root[T],root[T],1,dfsclock,1,tl-1);
            }
            if(is[v]==tim&&dfn[v]<tl&&dfn[v]!=1)
                change(root[T],root[T],1,dfsclock,dfn[v],dfn[v]+siz[v]-1);
        }
        ans+=1ll*sum[root[T]];
    	for(int v,i=head[now];i;i=Next[i])
    		if((v=to[i])!=fa&&!del[v])
                dfs(v,now);
        for(int i=0;i<yuu[now].size();i++) --buct[yuu[now][i].id];
        --T;
    }
    void Divide(int now)
    {
    	del[now]=1;
    	key[0]=dfsclock=0;
    	++tim;
    	dfs0(now,0);
    	root[T=0]=tot=0;
    	for(int i=0;i<yuu[now].size();i++) ++buct[yuu[now][i].id];
    	for(int v,i=head[now];i;i=Next[i])
    		if(!del[v=to[i]])
    		{
    		    T=0;//撤回到0但是东西前面树的东西还在
    		    for(int j=1;j<=key[0];j++)
                    change(root[T],root[T],1,dfsclock,dfn[key[j]],dfn[key[j]]+siz[key[j]]-1);
                key[0]=0;
                tl=dfn[v];
    		    dfs(v,now);
    		}
        for(int i=0;i<yuu[now].size();i++) --buct[yuu[now][i].id];
    	for(int v,i=head[now];i;i=Next[i])
    		if(!del[v=to[i]])
    		{
    			mi=si=siz[v];
    			dfsrt(v,now);
    			Divide(rt);
    		}
    }
    int main()
    {
    	read(n),read(m);
    	for(int u,v,i=1;i<n;i++)
    		read(u),read(v),add(u,v),add(v,u);
    	for(int a,b,i=1;i<=m;i++)
        {
            read(a),read(b);
            yuu[a].push_back(node(b,i));
            yuu[b].push_back(node(a,i));
    	}
    	mi=si=n,dfsrt(1,0),Divide(rt);
    	ans=1ll*n*(n-1)/2-ans;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    扫描线有机会补


    2019.2.22

  • 相关阅读:
    Android系统框架
    get请求在ie浏览器下有缓存
    select2的基本用法
    js 获取url中的查询字符串
    常用的正则验证
    此计算机当前已经连接限制为。。
    sharepoint 备份和还原site脚本
    sharepoint 删除list里的所有内容
    ajax调用服务的基本格式
    rest的config
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10420934.html
Copyright © 2011-2022 走看看