#1156 : 彩色的树
-
2 3 1 2 2 3 3 1 2 2 1 1 5 1 2 2 3 2 4 2 5 4 1 2 2 1 2 3 2 1
样例输出
-
Case #1: 1 3 Case #2: 1 5
描述
给定一棵n个节点的树,节点编号为1, 2, …, n。树中有n - 1条边,任意两个节点间恰好有一条路径。这是一棵彩色的树,每个节点恰好可以染一种颜色。初始时,所有节点的颜色都为0。现在需要实现两种操作:
1. 改变节点x的颜色为y;
2. 询问整棵树被划分成了多少棵颜色相同的子树。即每棵子树内的节点颜色都相同,而相邻子树的颜色不同。
输入
第一行一个整数T,表示数据组数,以下是T组数据。
每组数据第一行是n,表示树的节点个数。接下来n - 1行每行两个数i和j,表示节点i和j间有一条边。接下来是一个数q,表示操作数。之后q行,每行表示以下两种操作之一:
1. 若为"1",则询问划分的子树个数。
2. 若为"2 x y",则将节点x的颜色改为y。
输出
每组数据的第一行为"Case #X:",X为测试数据编号,从1开始。
接下来的每一行,对于每一个询问,输出一个整数,为划分成的子树个数。
数据范围
1 ≤ T ≤ 20
0 ≤ y ≤ 100000
小数据
1 ≤ n, q ≤ 5000
大数据
1 ≤ n, q ≤ 100000
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
int head[maxn],tot;
int col[maxn],fa[maxn];
int N,Q;
map<int,int> mp[maxn];
struct node
{
int v,next;
}edge[maxn*2];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(col,0,sizeof(col));
for(int i=0;i<=N;i++)mp[i].clear();
}
void add_edge(int u,int v)
{
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int pre)
{
fa[u]=pre;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==pre)continue;
mp[u][0]++;
dfs(v,u);
}
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
init();
for(int i=1;i<N;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0);
scanf("%d",&Q);
int ans=1;
int op,x,y;
printf("Case #%d:\n",cas++);
while(Q--)
{
scanf("%d",&op);
if(op==1)printf("%d\n",ans);
else
{
scanf("%d%d",&x,&y);
if(x!=1)
{
int tmp=fa[x];
if(col[x]!=col[tmp])ans--;
mp[tmp][col[x]]--,mp[tmp][y]++;
if(y!=col[tmp])ans++;
}
ans+=mp[x][col[x]]-mp[x][y];
col[x]=y;
}
}
}
return 0;
}
#1158 : 质数相关
-
3 5 2 4 8 16 32 5 2 3 4 6 9 3 1 2 3
样例输出
-
Case #1: 3 Case #2: 3 Case #3: 2
描述
两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。
输入
第一行为一个数T,为数据组数。之后每组数据包含两行。
第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。
输出
对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。
数据范围
1 ≤ T ≤ 20
集合S内的数两两不同且范围在1到500000之间。
小数据
1 ≤ N ≤ 15
大数据
1 ≤ N ≤ 1000
网络流:先求出每个数的质因子的个数,然后对于有偶数个质因子的数,与起点连边,奇数个的与终点连边,奇偶之间并且只差一个素数的连边,求最大流,用N减去就是答案
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int INF=1000000000;
const int limit=5*maxn;
int N;
int a[maxn];
int prime[limit],cnt[limit];
int n,m,k,nn,st,en;
int vis[maxn],pre[maxn];
int tot;
int dis[maxn],gap[maxn],cur[maxn],head[maxn];
struct node
{
int v,f,next;
}edge[maxn*2];
void add_edge(int x,int y,int f)
{
edge[tot].v=y;
edge[tot].f=f;
edge[tot].next=head[x];
head[x]=tot++;
edge[tot].v=x;
edge[tot].f=0;
edge[tot].next=head[y];
head[y]=tot++;
}
int SAP(int st,int en)
{
for(int i=0;i<=nn;i++)
{
cur[i]=head[i];
dis[i]=gap[i]=0;
}
int u=0;
int flow=0,aug=INF;
gap[st]=nn;
u=pre[st]=st;
bool flag;
while(dis[st]<nn)
{
flag=0;
for(int &j=cur[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].f>0&&dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].f<aug)aug=edge[j].f;
pre[v]=u;
u=v;
if(u==en)
{
flow+=aug;
while(u!=st)
{
u=pre[u];
edge[cur[u]].f-=aug;
edge[cur[u]^1].f+=aug;
}
aug=INF;
}
break;
}
}
if(flag)continue;
int mindis=nn;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(dis[v]<mindis&&edge[j].f>0)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0)break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
//线性求质因子个数
void process()
{
cnt[1]=0;
int len=0;
for(int i=2;i<limit;i++)
{
if(cnt[i]==0)
{
prime[len++]=i;
cnt[i]=1;
}
for(int j=0;j<len&&i*prime[j]<limit;j++)
{
cnt[i*prime[j]]=cnt[i]+1;
if(i%prime[j]==0)break;
}
}
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
bool judge(int x,int y)
{
if(x>y)swap(x,y);
if(y%x==0&&cnt[y]==cnt[x]+1)return true;
return false;
}
int main()
{
int T,cas=1;
scanf("%d",&T);
process();
while(T--)
{
scanf("%d",&N);
for(int i=1;i<=N;i++)scanf("%d",&a[i]);
init();
int ans=0;
st=0,en=N+1;
nn=en+1;
for(int i=1;i<=N;i++)
if(cnt[a[i]]%2==0)add_edge(st,i,1);
else add_edge(i,en,1);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(cnt[a[i]]%2==0&&cnt[a[j]]%2==1&&judge(a[i],a[j]))
add_edge(i,j,1);
printf("Case #%d: %d\n",cas++,N-SAP(st,en));
}
}