• [luogu6185]序列


    对于2操作,如果把这些操作看成边,那么对于某一个连通块内的若干个点,满足权值可以任意分配(证明:归纳,若n个点可以,那么先将新增的点调整好,再对原来n个点重新分配即可),因此可以将原图缩点,并将连通块的和作为新的权值
    1操作比较复杂,同样把其当成边连起来,形成一张图(包括自环),然后考虑图中的一个连通块
    对这张图,我们可以将操作复杂化:1.对一条长度为奇数的链,两端+1或-1;2.对一条长度为偶数的脸,两端一端+1,一端-1(转化的正确性容易证明)
    如果不存在奇环,那么可以二分图染色,之后相当于左右各是一张2操作的完全图,左右之间点权差不变,即需要满足差值与目标差值相同即可
    如果存在奇环,那么任意两点之间既存在一条奇数边,又存在一条偶数边,所以相当于既是2操作的完全图,又可以让总点权+2,那么只需要和与目标的和奇偶性相同即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 struct ji{
     5     int nex,to;
     6 }edge[N<<1];
     7 vector<int>v[3][N];
     8 int E,t,n,m,p,x,y,head[N],bl[N],a[N],b[N],sum[N];
     9 void add(int x,int y){
    10     edge[E].nex=head[x];
    11     edge[E].to=y;
    12     head[x]=E++;
    13 }
    14 void dfs1(int k){
    15     if (bl[k])return;
    16     bl[k]=x;
    17     sum[x]+=a[k]-b[k];
    18     for(int i=0;i<v[2][k].size();i++)dfs1(v[2][k][i]);
    19 }
    20 bool dfs2(int k,int p){
    21     if (bl[k]>=0)return bl[k]==p;
    22     if (p)x+=sum[k];
    23     else y+=sum[k];
    24     bl[k]=p;
    25     bool flag=1;
    26     for(int i=head[k];i!=-1;i=edge[i].nex)flag&=dfs2(edge[i].to,p^1);
    27     return flag;
    28 }
    29 int main(){
    30     scanf("%d",&t);
    31     while (t--){
    32         scanf("%d%d",&n,&m);
    33         E=0;
    34         memset(bl,0,sizeof(bl));
    35         memset(sum,0,sizeof(sum));
    36         memset(head,-1,sizeof(head));
    37         for(int i=1;i<=n;i++)v[1][i].clear();
    38         for(int i=1;i<=n;i++)v[2][i].clear();
    39         for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    40         for(int i=1;i<=n;i++)scanf("%d",&b[i]);
    41         for(int i=1;i<=m;i++){
    42             scanf("%d%d%d",&p,&x,&y);
    43             v[p][x].push_back(y);
    44             v[p][y].push_back(x);
    45         }
    46         x=0;
    47         for(int i=1;i<=n;i++)
    48             if (!bl[i]){
    49                 x++;
    50                 dfs1(i);
    51             }
    52         for(int i=1;i<=n;i++)
    53             for(int j=0;j<v[1][i].size();j++)add(bl[i],bl[v[1][i][j]]);
    54         memset(bl,-1,sizeof(bl));
    55         n=x;
    56         bool flag=1;
    57         for(int i=1;i<=n;i++)
    58             if (bl[i]<0){
    59                 x=y=0;
    60                 p=dfs2(i,0);
    61                 if (p)flag&=(x==y);
    62                 else flag&=((x+y)%2==0);
    63             }
    64         if (flag)printf("YES
    ");
    65         else printf("NO
    ");
    66     }
    67 }
    View Code
  • 相关阅读:
    一道小学数学题
    Ubuntu下使用git提交代码至GitHub
    C#几个小知识点
    C#中巧用#if DEBUG 进行调试
    使用 HPC Pack 为 Azure 中的 Windows HPC 工作负荷创建和管理群集的选项
    使用 Chef 自动执行 Azure 虚拟机部署
    在 Azure 中管理 Windows 虚拟机的可用性
    什么是 Azure 中的虚拟机规模集?
    从 Azure 下载 Windows VHD
    如何使用 Packer 在 Azure 中创建 Windows 虚拟机映像
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/12608269.html
Copyright © 2020-2023  润新知