zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:飘雪圣域(莫队)

    题目描述

      $IcePrincess ext{_}1968$和$IcePrince ext{_}1968$长大了,他们开始协助国王$IceKing ext{_}1968$管理国内事物。
      $IcePrincess ext{_}1968$和$IcePrince ext{_}1968$住在一个宁静悠远的王国:$IceKingdom$——飘雪圣域。飘雪圣域有$n$个城镇,编号$1,2,3...n$。有些城镇之间有道路,且满足任意两点之间有且仅有一条路径。飘雪圣域风景优美,但气候并不是太好。根据$IcePrince ext{_}1968$的气候探测仪,将来会发生$q$场暴风雪。每场暴风雪可以用两个整数$l_i,r_i$刻画,表示这场暴风雪之后,只有编号属于$[l_i,r_i]$的城市没有受到暴风雪的影响。
      在暴风雪的影响下迅速确定王国的农业生产方案是非常重要的事情。$IceKing ext{_}1968$认为,一个农业生产地域应该是一个极大连通块,满足每个节点都没有被暴风雪影响。这里极大连通块的定义是:不存在一个不属于该点集的未被暴风雪影响的点与该连通块连通。
      $IcePrincess ext{_}1968$要负责算出每次暴风雪后,王国能拥有多少个农业生产地域。注意这里每次暴风雪是独立的,即每次暴风雪过后,直到每个城镇重新焕发生机,下一次暴风雪才会到来。
      正如上文所述,$IcePrincess ext{_}1968$擅长文学但不擅长计算机,于是请你帮忙。


    输入格式

      输入文件名为$icekingdom.in$。
      第一行包含两个正整数$n,q$,表示$IceKingdom$的城镇个数和暴风雪次数。
      第$2$至第$n$行,每行两个正整数$x,y$,表示城镇$x$和城镇$y$之间有一条道路。
      第$n+1$至第$n+q$行,每行两个正整数$l_i,r_i$,描述一场暴风雪,含义如题面所述。


    输出格式

      输出文件名$icekingdom.out$。
      输出文件共有$q$行,第$i$行表示在第$i$场暴风雪之后农业生产地域的个数。


    样例

    样例输入:

    4 3
    1 2
    2 3
    2 4
    1 2
    1 3
    3 4

    样例输出:

    1
    1
    2


    数据范围与提示

    样例解释:

    第一次询问,只有$(1,2)$一个连通块。
    第二次询问,只有$(1,2,3)$一个连通块。
    第三次询问,有$3$和$4$两个连通块。

    数据范围:

    对于$30\%$的数据:$nleqslant 100,qleqslant 100$;
    对于$50\%$的数据:$nleqslant 2,000,qleqslant 2,000$;
    对于$100\%$的数据:$nleqslant 200,000,qleqslant 200,000$,对于所有的暴风雪,$l_ileqslant r_i$。


    题解

    官方正解中的两种做法都是用的数据结构,然而我用的是莫队……

    加一个点它对答案的贡献是$1-$与它连接的没有受到暴风雪影响的点,$1$是因为它自己可以作为一个新的联通块,减去没有收到暴风雪影响的点是因为它会合并这些联通块;删点同理。

    显然$200,000$的数据范围莫队一定要有$Theta(1)$修改的方法。

    不妨以加的操作为例,为做到$Theta(1)$修改,就需要找到方法快速求出与它连接的没有受到暴风雪影响的点。

    先预处理出来所有点的父亲,并设$num[x]$为点$x$的儿子中没有受到暴风雪影响的点的个数,加入一个点的同时将它父亲的$num+1$即可,注意统计答案时不要忘了父亲。

    删点同理。

    时间复杂度:$Theta(nsqrt{n})$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct node{int nxt,to;}e[500000];
    struct rec{int l,r,pos,id;}q[200001];
    int head[200001],cnt;
    int n,m;
    int ans[200001],l,r,now;
    int num[200001],fa[200001];
    bool vis[200001];
    void add(int x,int y)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	head[x]=cnt;
    }
    bool cmp(rec a,rec b){return (a.pos)^(b.pos)?a.l<b.l:(((a.pos)&1)?a.r<b.r:a.r>b.r);}
    void add(int x)
    {
    	vis[x]=1;
    	now++;
    	now-=num[x];
    	num[fa[x]]++;
    	if(vis[fa[x]])now--;
    }
    void del(int x)
    {
    	vis[x]=0;
    	now--;
    	now+=num[x];
    	num[fa[x]]--;
    	if(vis[fa[x]])now++;
    }
    void dfs(int x)
    {
    	for(int i=head[x];i;i=e[i].nxt)
    		if(!fa[e[i].to]&&e[i].to>1){fa[e[i].to]=x;dfs(e[i].to);}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int t=sqrt(n);
    	for(int i=1;i<n;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);add(y,x);
    	}
    	dfs(1);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].pos=(q[i].l-1)/t+1;
    		q[i].id=i;
    	}
    	sort(q+1,q+m+1,cmp);
    	l=r=1;add(1);
    	for(int i=1;i<=m;i++)
    	{
    		while(l>q[i].l)add(--l);
    		while(r<q[i].r)add(++r);
    		while(l<q[i].l)del(l++);
    		while(r>q[i].r)del(r--);
    		ans[q[i].id]=now;
    	}
    	for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Maven环境搭建、调试、打包
    JAVA环境变量JAVA_HOME、CLASSPATH、PATH设置详解
    Activiti工作流引擎核心介绍
    NodeJS概述
    JRE集成到Tomcat
    ORACLE递归查询(适用于ID,PARENTID结构数据表)
    爬虫入门——02
    爬虫入门——01
    利用java.lang.reflect.Constructor动态实例化对象
    【java入门点滴】向上转型与向下转型
  • 原文地址:https://www.cnblogs.com/wzc521/p/11678796.html
Copyright © 2011-2022 走看看