Lights

题目信息

题目链接

Luogu CF1907G

思路分析

如果我们把每一个关系都转化为一条无向边,则 \(n\) 个点会有 \(n\) 条边,并且每一个点的度数至少是 \(1\),所以是一颗基环树森林。我们分别看看每一个数。

一棵树一定会有一个环,首先环外树的决策方案是一定的,一定是将每一个权值为 \(1\) 的点上传到祖先上面,使得它们被一起消掉,最后上传到环上就行。

紧接着就是处理在环上的点就行。假设环上权值为 \(1\) 的点的编号为:\(a_1,a_2,\dots,a_n\)

  1. \(n\nmid2\)
    此时在环上的点不管怎样都不可能两两消掉。
  2. \(n\mid2\)
    此时我们有两种选择:
    • \(a_1\Leftrightarrow a_2,a_3\Leftrightarrow a_4,\dots,a_{n-1}\Leftrightarrow a_n\)
    • \(a_2\Leftrightarrow a_3,a_4\Leftrightarrow a_5,\dots,a_n\Leftrightarrow a_1\)
      我们只需要在这两种取最有情况就行了。

代码

#include<bits/stdc++.h>
using namespace std;
#pragma G++ optimize(1)
#pragma G++ optimize(2)
#pragma G++ optimize(3)
void read(int &x){
	x = 0;int p = 1;char ch;
	do{
		ch = getchar();
		if(ch=='-') p = -1;
	}while(!isdigit(ch));
	while(isdigit(ch)){
		x*=10;
		x+=ch-'0';
		ch = getchar();
	}
	x*=p;
}
void read(char &x){
    x = getchar();
    while(x==' '||x=='\n'||x=='\r') x = getchar();
}
void write(char x){
    putchar(x);
}
void write(int k){
	if(k<0) putchar('-');
	k = abs(k);
	stack<int> num;
	do{
		num.push(k%10);
		k/=10;
	}while(k);
	while(!num.empty()){
		putchar(num.top()+48);
        num.pop();
	}
}
const int MAXN = 2e5+10;
int T,n,loop1[MAXN],loop2[MAXN],floop1[MAXN],floop2[MAXN];
//graph
struct graph{
    struct EDGE{int x,y,nxt,from;}edge[MAXN];
    int h[MAXN],cnt;
    void new_edge(int x,int y,int from){
        edge[++cnt] = {x,y,h[x],from};
        h[x] = cnt;
    }
}v,tree;
//Topo
int inde[MAXN];
bitset<MAXN> loop,is;
void Topo(){
    queue<int> topo;
    for(int i = 1;i<=n;i++) if(!inde[i]) topo.push(i);
    while(!topo.empty()){
		int tmp = topo.front();topo.pop();loop[tmp] = 0;
		for(int pppi=v.h[tmp],i;pppi,i=v.edge[pppi].y;pppi=v.edge[pppi].nxt) 
			if(!(--inde[i])) topo.push(i);
	}
//	cout << loop[1] << " " << loop[2] << " " << loop[3] << " " << loop[4] << " " << loop[5] << endl;
}
void new_graph(){
    for(int i = 1;i<=n;i++){
        for(int pppj = v.h[i];pppj;pppj = v.edge[pppj].nxt){
            int j = v.edge[pppj].y;
            if(!loop[j]) tree.new_edge(i,j,v.edge[pppj].from);
            else if(!loop1[i]) loop1[i]=j,floop1[i]=v.edge[pppj].from;
            else loop2[i] = j,floop2[i]=v.edge[pppj].from;
        }
    }
}
//DP
vector<int> ans;
int dfs(int k,int fath){
    int sum = is[k];
    for(int pppp = tree.h[k];pppp;pppp = tree.edge[pppp].nxt){
        int i = tree.edge[pppp].y;
        if(i==fath) continue;
        int p = dfs(i,k);
        sum += p;
        if(p) ans.push_back(tree.edge[pppp].from);
    }
    return sum%2;
}
bitset<MAXN> vis;
int dfs_loop(int k,int from,int fath,vector<int> &ans){
    int sum = is[k];vis[k] = 1;int q = 0;
	if(k==from) return sum;
    if(loop1[k]!=fath){
		q++;
        int p = dfs_loop(loop1[k],from,k,ans);
        sum += p;
        if(p) ans.push_back(floop1[k]);
    }else if(loop2[k]!=fath){
		q++;
        int p = dfs_loop(loop2[k],from,k,ans);
        sum += p;
        if(p) ans.push_back(floop2[k]);
    }
	if(!q){
		int p = dfs_loop(loop1[k],from,k,ans);
		sum += p;
		if(p) ans.push_back(floop1[k]);
	}
    return sum%2;
}
//Normal
void clear(){
    vis.reset();loop.reset();ans.clear();
    v.cnt = tree.cnt = 0;
    for(int i = 1;i<=n;i++){
		v.h[i] = 0;tree.h[i] = 0;
        inde[i] = 0;
        loop[i] = 1;
        loop1[i] = 0;
        loop2[i] = 0;
		floop1[i] = 0;
		floop2[i] = 0;
    }
}
signed main(){
    read(T);
    while(T--){
//		if(T==9888){
//			cin >> n;cout << n;
//			string x;
//			cin >> x;cout << x << endl;
//			for(int i = 1;i<=n;i++){
//				int x;
//				cin >>x ;
//				cout << x << " ";
//			}
//			return 0;
//		}
		read(n);
		clear();
        for(int i = 1;i<=n;i++){
            char k;
            read(k);
            is.set(i,k-'0');
        }
        for(int i = 1;i<=n;i++){
            int x;
            read(x);
			inde[x]++;
            v.new_edge(i,x,i);
            v.new_edge(x,i,i);
        }
        Topo();new_graph();
//		for(int pppp = tree.h[9],i;pppp,i=tree.edge[pppp].y;pppp=tree.edge[pppp].nxt) cout << i << endl;
        for(int i = 1;i<=n;i++){
            if(loop[i]){
                int sum = is[i];
                for(int pppj=tree.h[i],j;pppj,j=tree.edge[pppj].y;pppj=tree.edge[pppj].nxt){
                    int p = dfs(j,i);
                    sum += p;
                    if(p) ans.push_back(tree.edge[pppj].from);
                }
                is.set(i,sum%2);
            }
        }
		bool fg = 1;
        for(int i = 1;i<=n;i++){
            if(loop[i]&&!vis[i]&&is[i]){
                vector<int> ans1,ans2;
                int k = dfs_loop(loop1[i],i,i,ans1);
                dfs_loop(loop2[i],i,i,ans2);
				if(k&1) fg  = 0;
                if(ans1.size()>ans2.size()) swap(ans1,ans2);
                for(int i:ans1) ans.push_back(i);
            }
        }
		if(fg){
        write((int)ans.size());write('\n');
        for(int i:ans) write(i),write(' ');
        write('\n');
		}else puts("-1");
    }
    return 0;
}

tag

Codeforces
图论基环树拓扑排序DFS

posted @ 2024-06-24 13:59  GuTongXing  阅读(21)  评论(0)    收藏  举报