QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#385970#6127. Kawa ExamGuchenxi0971TL 3ms35392kbC++144.8kb2024-04-11 10:40:042024-04-11 10:40:05

Judging History

你现在查看的是最新测评结果

  • [2024-04-11 10:40:05]
  • 评测
  • 测评结果:TL
  • 用时:3ms
  • 内存:35392kb
  • [2024-04-11 10:40:04]
  • 提交

answer

#include <bits/stdc++.h>
using namespace std;
const int Max=2e5+10;


struct Node{
	int to,next,u,id;
	Node(int to=0,int next=0,int u=0,int id=0):
		to(to),next(next),u(u),id(id){;}
}a[Max<<1],B[Max<<1];
int head[Max],cnt=0;
void add(int x,int y,int id){
	a[++cnt]=Node(y,head[x],x,id);
	head[x]=cnt;
}

int Cnt=1;
void Add(int x,int y,int id){
	B[++Cnt]=Node(y,head[x],x,id);
	head[x]=Cnt;
}

struct Tree{
	int fa,siz,son,top,l,r,id;
	#define siz(x) b[x].siz
	#define son(x) b[x].son
	#define top(x) b[x].top
	#define fa(x) b[x].fa
	#define id(x) b[x].id
	#define l(x) b[x].l
	#define r(x) b[x].r
}b[Max];

void dfs1(int now,int fa){
	fa(now)=fa;
	siz(now)=1;
	l(now)=0;
	son(now)=0;
	for(int i=head[now];i;i=a[i].next){
		int to=a[i].to;
		if(to!=fa){
			dfs1(to,now);
			siz(now)+=siz(to);
			son(now)=siz(son(now))>siz(to)?son(now):to;
		}
	}
}

int Res=0; 

void dfs2(int now,int top){
	top(now)=top;
	l(now)=++Res;
	id(Res)=now;
	if(son(now)){
		dfs2(son(now),top);
	}
	for(int i=head[now];i;i=a[i].next){
		int to=a[i].to;
		if(!l(to))dfs2(to,to);
	}
	r(now)=Res;
}



int Sum[Max],NumSum[Max],Pos[Max],NumPos[Max],MaxSum,MaxPos;
vector<int>Val[Max];
int res[Max];
/*
Sum表示这个颜色有几个
NumSum[i]表示Sum[j]为i的j有几个
MaxSum表示最大的Sum[i]
Sum为当前子树内部的节点信息 


Pos同理
Pos为子树外的节点信息 
*/

void WorkSum(int val,int sum){
	if(sum==1){
		NumSum[Sum[val]]--;
		if(MaxSum==Sum[val])MaxSum++;
		Sum[val]++;
		NumSum[Sum[val]]++;
	}else{
		NumSum[Sum[val]]--;
		Sum[val]--;
		NumSum[Sum[val]]++;
		if(!NumSum[MaxSum])MaxSum--;
	}
}

void WorkPos(int val,int sum){ 
	if(sum==1){
		NumPos[Pos[val]]--;
		if(MaxPos==Pos[val])MaxPos++;
		Pos[val]++;
		NumPos[Pos[val]]++;
	}else{
		NumPos[Pos[val]]--;
		Pos[val]--;
		NumPos[Pos[val]]++;
		if(!NumPos[MaxPos])MaxPos--;
	}
}

int skp;

void Work(int now,int z){
	for(int i=l(now);i<=r(now);++i){
		if(id(i)==skp){
			i=r(id(i));
			continue;
		}
		for(int j:Val[id(i)]){
			WorkSum(j,1*z);
			WorkPos(j,-1*z);
		}
	}
}

int Vis[Max];

void Dsu(int now,int id,int K){
	Vis[now]=1;
	int RRR=0;
	for(int i=head[now];i;i=a[i].next){
		int to=a[i].to;
		if(to==son(now))RRR=a[i].id;
		if(to==fa(now)||to==son(now))continue;
		Dsu(to,a[i].id,K);
	}
	if(son(now)){
		Dsu(son(now),RRR,K);
		skp=son(now);
	}
	
	Work(now,1);
	res[id]=MaxSum+MaxPos-K;
	
	if(now==top(now)){
		skp=0;
		Work(now,-1);
	}
}

int low[Max],dfn[Max];
vector<vector<int> > ans;
int Sta[Max],opt;

void Work(int now){
	vector<int>s;
	for(int i=0;i!=now;){
		s.push_back(i=Sta[opt--]);
	}
	ans.push_back(s);
}


int pos=0;
void dfs(int now,int z){
	low[now]=dfn[now]=++pos;
	Sta[++opt]=now;
	for(int i=head[now];i;i=B[i].next){
		int to=B[i].to;
		if(i==(z^1))continue;
		if(!dfn[to]){
			dfs(to,i);
			low[now]=min(low[now],low[to]);
			if(low[to]>dfn[now])Work(to);
		}else{
			low[now]=min(low[now],dfn[to]);
		}
	}
}

int val[Max],fa[Max];


void dfs3(int now,int opt){
	if(opt) for(int j:Val[now]) WorkPos(j,1);//cout << j << ' ';
	else for(int j:Val[now])WorkPos(j,-1);
	for(int i=head[now];i;i=a[i].next){
		int to=a[i].to;
		if(to!=fa(now))dfs3(to,opt);
	}
}

void Clear(){
	memset(NumSum,0,sizeof(NumSum));
	memset(NumPos,0,sizeof(NumPos));
	memset(head,0,sizeof(head));
	memset(Vis,0,sizeof(Vis));
	memset(Pos,0,sizeof(Pos));
	memset(Sum,0,sizeof(Sum));
	memset(res,0,sizeof(res));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(Sta,0,sizeof(Sta));
	memset(fa,0,sizeof(fa));
	memset(b,0,sizeof(b)) ;
	ans.clear();
	skp=opt=pos=Res=MaxPos=MaxSum=0;
	Cnt=1;
	cnt=0;
}


void work(){
	Clear();
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&val[i]);
	for(int i=1;i<=m;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		Add(x,y,i);
		Add(y,x,i);
	}
	for(int i=1;i<=n;++i){
		if(!dfn[i]){
			dfs(i,0);
			Work(i);
		}
	}
	int pos=n;
	memset(head,0,sizeof(head));
	for(auto S:ans){
		++pos;
		Val[pos].clear();
		for(int i:S){
			fa[i]=pos;
			Val[pos].push_back(val[i]);
		}
	}
	for(int i=2;i<=Cnt;i+=2){
		int to=B[i].to;
		int u=B[i].u;
		if(fa[to]!=fa[u]){
			add(fa[to],fa[u],B[i].id);
			add(fa[u],fa[to],B[i].id);
		}
	}
	
	NumPos[0]=NumSum[0]=INT_MAX;
	int R=0;
	
	for(int i=n+1;i<=pos;++i){
		if(!Vis[i]){
			dfs1(i,0);
			dfs2(i,i);
			dfs3(i,1);
			R+=MaxPos;
			Dsu(i,0,MaxPos);
			dfs3(i,0);
		}
	}
	
	for(int i=1;i<=m;++i){
		cout << res[i]+R;
		if(i!=m)putchar(' ');
	}
}

signed main(){
	int T;
	scanf("%d",&T);
	while(T--){
		work();
		if(T)cout << "\n";
	}
	
	return 0;
}
/*
通过给定的边建图,边双缩点,必定形成森林。
对于每棵树dsu on tree。 
*/

詳細信息

Test #1:

score: 100
Accepted
time: 3ms
memory: 35392kb

input:

3
7 5
1 2 1 2 1 2 1
1 2
1 3
2 4
5 6
5 7
3 3
1 2 3
1 2
1 3
2 3
2 3
12345 54321
1 2
1 2
1 1

output:

6 5 5 5 4
1 1 1
1 1 1

result:

ok 3 lines

Test #2:

score: -100
Time Limit Exceeded

input:

5557
2 7
79960 79960
2 2
1 1
1 1
2 2
1 1
2 1
1 2
9 8
21881 70740 70740 21881 22458 22458 639 21881 70740
3 3
1 6
5 8
7 5
5 7
2 3
5 1
7 6
6 7
13064 20716 6746 13064 6746 69225
5 5
4 1
4 1
1 6
4 5
3 2
3 2
8 4
45146 14400 45146 45146 14400 72969 14400 45146
8 6
1 3
4 6
8 3
18 13
48132 37949 92338 92338...

output:

2 2 2 2 2 2 2
6 6 7 6 6 6 6 6
3 3 3 4 4 3 3
7 7 7 7
9 9 9 8 9 8 9 8 9 9 10 9 9
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
7 8
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
9 10 9
16 16 16 16 16 17 16 16
10 10 11 10 12 11 10 10 10 10 10 10 10 12 10 10 10 10 10 11
10 9 9 9 9 9 9 9 9 9 9 9 9 9 10 ...

result: