BZOJ2278: [Poi2011]Garbage

111 篇文章 0 订阅
3 篇文章 0 订阅
题目大意:给定n个点m条边,每条边有一个初始权值0或1,有一个最终权值0或1,每次可以给一个简单环上的边权值异或1,求一种方案使得每条边从初始权值变成最终权值

一看这个样子就知道不需要该变的边没啥用,因为反正都要变两次,不如把这两次合起来,然后这些边不变..
然后我就写了一个找欧拉回路的算法,交上去WA了....


然后就要了数据,发现需要特判单独的点,否则会输出一些奇怪的东西....
然后还是WA
TAT||||

为啥题里没说“必须是简单环”啊,这样欧拉回路就不行了....那我们可以维护一个像栈一样的东西遇到一个环就弹出去
再交一发TLE...

然后就想起来毛啸出的那道coloring....也就是邻接表求欧拉回路的时间复杂度会退化到O(N^2)
所以就要用到类似网络流的当前弧优化的东西

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define N 1000010
using namespace std;
int to[N<<1],nxt[N<<1],num[N<<1],pre[N],cnt;
void NO(){puts("NIE");exit(0);}
void ae(int ff,int tt)
{
	cnt++;
	to[cnt]=tt;
	nxt[cnt]=pre[ff];
	pre[ff]=cnt;
	num[cnt]=(cnt-1)/2;
}
int du[N];
bool used[N],vis[N];
int fark;
void dfs(int x)
{
	fark++;
	used[x]=true;
	int i,j;
	for(i=pre[x];i;i=nxt[i])
	{
		j=to[i];
		if(used[j]) continue;
		dfs(j);
	}
}
vector<int>V[N];
int tot;
bool zai[N];
int s[N],t;
void dfs2(int x)
{
	used[x]=true;
	if(zai[x])
	{
		tot++;
		V[tot].push_back(x);
		while(s[t]!=x)
		{
			zai[s[t]]=false;
			V[tot].push_back(s[t]);
			t--;
		}
		zai[s[t]]=false;
		V[tot].push_back(s[t]);
		t--;
	}
	int i,j;
	for(i=pre[x];i;i=pre[x])
	{
		pre[x]=nxt[i];
		if(!vis[num[i]])
		{
			zai[x]=true;
			t++;s[t]=x;
			vis[num[i]]=true;
			dfs2(to[i]);
		}
	}
}
char ch,B[1<<15],*S=B,*T=B;
#define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
int main()
{
	int n,m;
	n=read();m=read();
	int i,j,x,y,u,v;
	while(m--)
	{
		x=read();y=read();u=read();v=read();
		if(u!=v)
		{
			du[x]++;du[y]++;
			ae(x,y),ae(y,x);
		}
	}
	for(i=1;i<=n;i++)
	if(du[i]&1) NO();
	for(i=1;i<=n;i++)
	if(!used[i])
	dfs2(i);
	printf("%d\n",tot);
	for(i=1;i<=tot;i++)
	{
		printf("%d ",V[i].size()-1);
		for(j=0;j<V[i].size();j++)
		printf("%d ",V[i][j]);
		puts("");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值