hdu 6251 Inkopolis [Tarjan+想法]

题意:给你一个基环树,树上的边有各种颜色,每次操作有两种:

①修改一条边的颜色

②询问这个图有多少色块(相同颜色的边公用一个点,则为一块)

题解:(由于一遍一遍的改,代码很不精简=。=)

首先,我们可以考虑修改树上的边那么有7种情况:(假设边原来的颜色为a,修改后为b)

①边的两端的都存在颜色为a的边,修改后边的两端都存在颜色为b的边,则贡献为0。

②边的两端的都存在颜色为a的边,修改后边的两端有一端存在颜色为b的边,则贡献为1。

③边的两端的都存在颜色为a的边,修改后边的两端都不存在颜色为b的边,则贡献为2。

④边的两端有一端存在颜色为a的边,修改后边的两端都存在颜色为b的边,则贡献为-1。

⑤边的两端都不存在颜色为a的边,修改后边的两端都存在颜色为b的边,则贡献为-2。

⑥边的两端都不存在颜色为a的边,修改后边的两端有一端存在颜色为b的边则贡献为-1。

⑦边的两端有一端存在颜色为a的边,修改后边的两端都不存在颜色为b的边,则贡献为1。

其他情况贡献均为0。

然后我们考虑环上的情况

假如环是如下情况:

hdu 6251 Inkopolis [Tarjan+想法]_第1张图片

当加入颜色不是1的边时需要比之前条件的贡献-1

假如环时如下情况

hdu 6251 Inkopolis [Tarjan+想法]_第2张图片

当加入颜色是1的边时需要比之前条件的贡献+1

最后,与点相邻的边就直接加入set维护,Tarjan找基环,mp记录边的情况mp<0代表该边时环边。

AC代码:

#include
#include
#include
#include
#include
#include
#include
#include
#define N 200005
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}

struct edge
{
	int to,next,col;
	edge(){}
	edge(int to,int next,int col)
	{
		this->to=to;
		this->next=next;
		this->col=col;
	}
}ed[N*2];
int head[N],dfn[N],mark[N*2],cir[N],sta[N],low[N];
int lnum,index,tot,top,sum;
void addline(int a,int b,int c)
{
	ed[lnum]=edge(b,head[a],c);
	head[a]=lnum++;
}
void dfs(int u)
{
	dfn[u]=low[u]=++index;
	sta[top++]=u;
	for(int i=head[u];~i;i=ed[i].next)
	{
		int to=ed[i].to;
		if(mark[i])continue;
		mark[i]=mark[i^1]=1;
		if(!dfn[to])
		{
			dfs(to);
			low[u]=min(low[u],low[to]);
		}
		else low[u]=min(low[u],dfn[to]);
	}
	if(low[u]==dfn[u])
	{
		int now=tot,k;
		do
		{
			k=sta[--top];
			cir[tot++]=k;
		}while(k!=u);
		if(tot-now==1)tot=now;
	}	
}
struct node
{
	int col,num;
	node(){}
	node(int col,int num)
	{
		this->col=col;
		this->num=num;
	}
};
multisetst[N];
multiset::iterator it2;
multisetci;
multiset::iterator it,haha;
mapmp[N];
bool operator<(node a,node b)
{
	return a.col=n)printf("%d\n",sum);
				continue;
			}
			sum+=judge(a,b,c);
			if(mp[a][b]<0)
			{
				it=ci.find(node(abs(mp[a][b]),0));
				node k=*it;
				if(k.num==tot&&k.col!=c)
				{
					sum--;
					k.num--;
					ci.erase(it);
					ci.insert(k);
					ci.insert(node(c,1));
				}
				else if(k.num==1&&ci.size()==2)
				{
					haha=it;
					if(haha==ci.begin())haha++;
					else haha--;
					node g=*haha;
					if(g.col==c)sum++;
					ci.erase(it);
					it=ci.find(node(c,0));
					if(it==ci.end())ci.insert(node(c,1));
					else 
					{
						g=*it;
						g.num++;
						ci.erase(it);
						ci.insert(g);
					}
				}
				else 
				{
					k.num--;
					ci.erase(it);
					ci.insert(k);
					it=ci.find(node(c,0));
					if(it==ci.end())ci.insert(node(c,1));
					else 
					{
						k=*it;
						k.num++;
						ci.erase(it);
						ci.insert(k);
					}
				}
				mp[a][b]=mp[b][a]=-c;
			}
			else mp[a][b]=mp[b][a]=c;
			if(gg>=n)printf("%d\n",sum);
		}
	}
} 

你可能感兴趣的:(想法题,Tarjan,边双联通分量,想法)