[CSP-S模擬測試]:飄雪聖域(莫隊)

題目描述

  $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$長大了,他們開始協助國王$IceKing\text{_}1968$管理國內事物。
  $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$住在一個寧靜悠遠的王國:$IceKingdom$——飄雪聖域。飄雪聖域有$n$個城鎮,編號$1,2,3...n$。有些城鎮之間有道路,且知足任意兩點之間有且僅有一條路徑。飄雪聖域風景優美,但氣候並非太好。根據$IcePrince\text{_}1968$的氣候探測儀,未來會發生$q$場暴風雪。每場暴風雪能夠用兩個整數$l_i,r_i$刻畫,表示這場暴風雪以後,只有編號屬於$[l_i,r_i]$的城市沒有受到暴風雪的影響。
  在暴風雪的影響下迅速肯定王國的農業生產方案是很是重要的事情。$IceKing\text{_}1968$認爲,一個農業生產地域應該是一個極大連通塊,知足每一個節點都沒有被暴風雪影響。這裏極大連通塊的定義是:不存在一個不屬於該點集的未被暴風雪影響的點與該連通塊連通。
  $IcePrincess\text{_}1968$要負責算出每次暴風雪後,王國能擁有多少個農業生產地域。注意這裏每次暴風雪是獨立的,即每次暴風雪事後,直到每一個城鎮從新煥發生機,下一次暴風雪纔會到來。
  正如上文所述,$IcePrincess\text{_}1968$擅長文學但不擅長計算機,因而請你幫忙。
node


輸入格式

  輸入文件名爲$icekingdom.in$。
  第一行包含兩個正整數$n,q$,表示$IceKingdom$的城鎮個數和暴風雪次數。
  第$2$至第$n$行,每行兩個正整數$x,y$,表示城鎮$x$和城鎮$y$之間有一條道路。
  第$n+1$至第$n+q$行,每行兩個正整數$l_i,r_i$,描述一場暴風雪,含義如題面所述。
c++


輸出格式

  輸出文件名$icekingdom.out$。
  輸出文件共有$q$行,第$i$行表示在第$i$場暴風雪以後農業生產地域的個數。
數據結構


樣例

樣例輸入:dom

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

樣例輸出:blog

1
1
2
it


數據範圍與提示

樣例解釋:io

第一次詢問,只有$(1,2)$一個連通塊。
第二次詢問,只有$(1,2,3)$一個連通塊。
第三次詢問,有$3$和$4$兩個連通塊。
class

數據範圍:方法

對於$30\%$的數據:$n\leqslant 100,q\leqslant 100$;
對於$50\%$的數據:$n\leqslant 2,000,q\leqslant 2,000$;
對於$100\%$的數據:$n\leqslant 200,000,q\leqslant 200,000$,對於全部的暴風雪,$l_i\leqslant r_i$。


題解

官方正解中的兩種作法都是用的數據結構,然而我用的是莫隊……

加一個點它對答案的貢獻是$1-$與它鏈接的沒有受到暴風雪影響的點,$1$是由於它本身能夠做爲一個新的聯通塊,減去沒有收到暴風雪影響的點是由於它會合並這些聯通塊;刪點同理。

顯然$200,000$的數據範圍莫隊必定要有$\Theta(1)$修改的方法。

不妨以加的操做爲例,爲作到$\Theta(1)$修改,就須要找到方法快速求出與它鏈接的沒有受到暴風雪影響的點。

先預處理出來全部點的父親,並設$num[x]$爲點$x$的兒子中沒有受到暴風雪影響的點的個數,加入一個點的同時將它父親的$num+1$便可,注意統計答案時不要忘了父親。

刪點同理。

時間複雜度:$\Theta(n\sqrt{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\n",ans[i]);
	return 0;
}

rp++

相關文章
相關標籤/搜索