周练

CF701E
思路:这是第一次对于贡献这两个字有了一定的理解。
易得:每条边经过的次数=min(这条边左边学校个数,这条边右边需要的学校个数),为了能够达到最大,就尽量能走的边都走一遍,也就是把所有边对于答案的贡献加起来;此处看来,贡献仿佛就是可以对答案产生影响但又不一定必须要选择

int n,k,mark[maxn],cnt,head[maxn],vis[maxn],val[maxn];
ll ans=0;
struct Edge
{
    int v,next;
}edge[maxn<<1];
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void Initial()
{
    memset(val,0,sizeof(val));
    memset(head,-1,sizeof(head));
    memset(mark,0,sizeof(mark));
    memset(edge,0,sizeof(edge));
    cnt=0;ans=0;
}
void dfs(int now)
{
    if(vis[now])
        return ;
    //printf("now=%d,ans=%d\n",now,ans);
    vis[now]=1;
    if(mark[now])
        val[now]=1;
    for(int i=head[now];~i;i=edge[i].next)
    {
        int v=edge[i].v;
        if(vis[v])
            continue ;
        dfs(v);
        val[now]+=val[v];
        //printf("vnow=%d,vv=%d\n",val[now],val[v]);
    }
    ans+=(ll)min(val[now],2*k-val[now]);
    vis[now]=0;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        Initial();
        for(int i=1;i<=k*2;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            mark[tmp]=1;
        }
        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);
        printf("%lld\n",ans);
    }
    return 0;
}

poj1988(节点带权值的并查集)
思路:我们要查询经过一系列操作后某个方块下的个数,就直接维护每个方块下的方块个数,但是要顺带维护树的节点的个数,
在这里插入图片描述
如图标出的是节点权值
首先是Find函数,直接更新即可,比如样例中2那一坨放到6上面后,2的权值还未更新,仍是1。使用find函数吧途径节点的权值全部加起来。
然后是Union函数,一开始2和4位于同一颗树上,6和1位于同一个树上,大小均为2,将f[4]改为6时,val[4]+=size[6],也就是加上父节点所在树的大小(=2);同时父节点的大小也要更新,因为多了一棵子树。

//直接主函数
int p,siz[maxn],f[maxn],val[maxn];
void Initial()
{
    for(int i=1;i<=p;i++)
    {
        f[i]=i;
        val[i]=0;
        siz[i]=1;
    }
}
int myfind(int x)
{
   // printf("mfind: x=%d\n",x);
    if(x==f[x])
        return f[x];
    int tmp=f[x];
    f[x]=myfind(f[x]);
    val[x]+=val[tmp];
    return x=f[x];
}
void Union(int x,int y)
{
    int fx=myfind(x);
    //printf("heh\n");
    int fy=myfind(y);
    //printf("fx=%d,fy=%d\n",fx,fy);
    if(fx!=fy)
    {
       // printf("fx=%d.fy=%d\n",fx,fy);
        f[fx]=fy;
        val[fx]+=siz[fy];
        siz[fy]+=siz[fx];
    }
}
int main()
{
    scanf("%d",&p);
    Initial();
    while(p--)
    {
        char ch;
        cin>>ch;
        if(ch=='M')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            Union(x,y);
        }
        else if(ch=='C')
        {
            int x;
            scanf("%d",&x);
           // printf("val=%d\n",val[x]);
            int fx=myfind(x);
            printf("%d\n",val[x]);
        }
    }
    return 0;
}

hdu1811(拓扑排序+并查集)
思路:先处理相等的关系,将所有相等的点看成一点,不影响排序的结果,然后再利用拓扑排序看是否能排出一个序列出来,这一点我之前学习的时候没有注意到
1.若进入队列的点数小于总的点的数量,则必定存在环;等于则是一个无环图。
2.若队列中的点的数量大于了1,那么此时处于队列中的点之间的关系是不确定的。
代码:

int n,m,f[maxn],in[maxn],flag;
vector<int>v[maxn];
string ans[4];
struct STR
{
    int a,b;
    char ch;
}str[maxn*2];
int Find(int x)
{
    if(f[x]==x)
        return f[x];
    return f[x]=Find(f[x]);
}
void Initial()
{
    flag=1;
    for(int i=1;i<=n;i++)
    {
        v[i].clear();
        f[i]=i;
        in[i]=0;
    }
}
void tp()
{
    queue<int>q;
    while(!q.empty()) q.pop();
    int cnt=0,num=0;
    //printf("fi=%d\n",Find(1));
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            num++;
            if(in[i]==0)
            {
            //printf("fi=%d\n",fi);
                q.push(i);
            }
        }

    }
    while(!q.empty())
    {
        if(q.size()>=2)
        {
            flag=2;
        }
        int u=q.front();q.pop();cnt++;//printf("u=%d,cn=%d\n",u,v[u].size());
        for(int i=0;i<v[u].size();i++)
        {
            int to=v[u][i];
            //printf("t=%d,to=%d\n",t,to);
            in[to]--;
            if(in[to]==0)
            {
                q.push(to);
            }
        }
    }
  // printf("cbnt=%d\n",cnt);
    if(cnt<num)
        flag=3;
}
int main()
{
     ans[1]=ans[1]+"OK";
    ans[2]=ans[2]+"UNCERTAIN";
    ans[3]=ans[3]+"CONFLICT";
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        Initial();
        flag=1;
        for(int i=1;i<=m;i++)
        {
            cin>>str[i].a>>str[i].ch>>str[i].b;
            str[i].a++;str[i].b++;
            //printf("%d    b=%d\n",a,b);
            int fa=Find(str[i].a),fb=Find(str[i].b);
            //printf("a=%d,b=%d,fa=%d,fb=%d\n",a,b,fa,fb);
            if(str[i].ch=='=')
                f[fa]=fb;
        }
        for(int i=1;i<=m;i++)
        {
            if(str[i].ch=='=')
                continue;
            if(str[i].ch=='<')
            {
               int fa=Find(str[i].a),fb=Find(str[i].b);
               in[fa]++;
               v[fb].push_back(fa);
            }
            else if(str[i].ch=='>')
            {
                int fa=Find(str[i].a),fb=Find(str[i].b);
               in[fb]++;
               v[fa].push_back(fb);
            }
        }
        tp();
        cout<<ans[flag]<<endl;
    }
    return 0;
}

发布了33 篇原创文章 · 获赞 14 · 访问量 431

猜你喜欢

转载自blog.csdn.net/qq_44077455/article/details/103072760