• Codeforces Round #395 (Div. 1)


    比赛链接:http://codeforces.com/contest/763

    A题:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 const int N=100005;
     8 int n,tot,now[N],prep[N<<1],son[N<<1],c[N],a[N];
     9 void read(int &x){
    10     x=0; int f=1; char ch;
    11     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') f=-1;
    12     for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; x*=f;
    13 }
    14 void add(int u,int v){tot++,prep[tot]=now[u],now[u]=tot,son[tot]=v;}
    15 int main(){
    16     read(n);
    17     for (int u,v,i=1;i<n;i++){
    18         read(u),read(v);
    19         add(u,v),add(v,u);
    20     }
    21     for (int i=1;i<=n;i++) read(c[i]);
    22     for (int i=1;i<=n;i++)
    23     for (int j=now[i],k=son[j];j;j=prep[j],k=son[j]){
    24         if (i<k&&c[i]!=c[k]) a[i]++,a[k]++;
    25     }
    26     int cnt=0,id;
    27     for (int i=1;i<=n;i++) if (a[i]>=2) cnt++,id=i;
    28     if (cnt>1) puts("NO");
    29     else if (cnt==1){
    30         for (int i=now[id],j=son[i];i;i=prep[i],j=son[i]) if (c[id]!=c[j]) a[j]--;
    31         for (int i=1;i<=n;i++) if (i!=id&&a[i]){puts("NO");return 0;}
    32         puts("YES"); printf("%d
    ",id);
    33     }else{
    34         cnt=0;
    35         for (int i=1;i<=n;i++) if (a[i]) cnt++,id=i;
    36         if (cnt>2) puts("NO");
    37         else if (cnt==2) printf("YES
    %d
    ",id);
    38         else printf("YES
    %d
    ",1);
    39     }
    40     return 0;
    41 }
    View Code

      题目大意:给定一棵n个节点的树,每个点有个颜色,询问是否能以某个点为树根时,所有节点(树根除外)的子树中的颜色一致,有则输出YES,且输出树根的编号,否则输出NO; n,color[i]<=10^5;

      做法:很容易yy出一种做法,就是记录每个点周围与它颜色不一致的节点个数,显然我们把这个值最大的那个点作为树根时最有可能合法嘛,那么找出树根,大力check一下即可。

    B题:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 int main(){
     8     int n,x1,y1,x2,y2;
     9     cin>>n; puts("YES");
    10     while (n--){
    11         cin>>x1>>y1>>x2>>y2;
    12         cout<<(x1&1)*2+(y1&1)+1<<endl;
    13     }
    14     return 0;
    15 }
    View Code

      题目大意:给你n(n<=500000)个矩形,边长为奇数,矩阵不能相交,但是能相邻(也就是边有交集,且len>0),我们要用4种颜色去给矩形染色,要求相邻的矩形颜色不同,存在方案,则输出YES,并且要输出每个矩形的颜色,1<=color<=4,否则输出NO;

      做法:根据数学中的四色定理可知,一定存在某种方案,那么,我们该怎么构造一种方案,这题有个重要的性质,边长为奇数,奇数有什么性质?奇数+奇数=偶数,偶数+奇数=奇数,也就是说一个数加上一个奇数,那么这个数的奇偶性就会发生改变,一种神奇的思路:取矩形的左上端点(x,y)来分类,

    1.x为奇数,y为偶数,染为颜色1;

    2.x为奇数,y为奇数,染为颜色2;

    3.x为偶数,y为偶数,染为颜色3;

    4.x为偶数,y为奇数,染为颜色4;

    证明:如果两个矩形相邻,设这2个矩形的左上端点为(x1,y1),(x2,y2),由于矩形的边长为奇数,(x1,x2奇偶性不同),(y1,y2奇偶性不同)这两个条件至少成立一个,此时他们一定具有不同的颜色,得证。

    E题:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 #include <vector>
      7 #define PI pair<int,int>
      8 #define mp(a,b) make_pair(a,b)
      9 using namespace std;
     10 const int N=100005,M=N*6,K=N*5;
     11 int n,k,m,q,wi[K][2],fa[M],ans[N],son[M][2],smax[M],val[M],smax_id[M],tree[N];
     12 vector <PI> vec[N],a[N];
     13 void read(int &x){
     14     x=0; int f=1; char ch;
     15     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') f=-1;
     16     for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; x*=f;
     17 }
     18 struct T{
     19     int lowbit(int x){return x&(-x);}
     20     void insert(int x,int y){for (int i=x;i<=n;i+=lowbit(i)) tree[i]+=y;}
     21     int query(int x){
     22         int sum=0;
     23         for (int i=x;i;i-=lowbit(i)) sum+=tree[i];
     24         return sum;
     25     }
     26 }t;
     27 struct link_cut_tree{
     28     bool rev[M];
     29     int which(int x){return son[fa[x]][1]==x;}
     30     bool isroot(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
     31     void update(int x){
     32         smax[x]=val[x],smax_id[x]=x;
     33         if (son[x][0]&&smax[son[x][0]]>smax[x]) smax[x]=smax[son[x][0]],smax_id[x]=smax_id[son[x][0]];
     34         if (son[x][1]&&smax[son[x][1]]>smax[x]) smax[x]=smax[son[x][1]],smax_id[x]=smax_id[son[x][1]];        
     35     }
     36     void pushdown(int x){
     37         if (!rev[x]) return;
     38         rev[x]^=1,swap(son[x][0],son[x][1]);
     39         if (son[x][0]) rev[son[x][0]]^=1;
     40         if (son[x][1]) rev[son[x][1]]^=1;
     41     }
     42     void relax(int x){
     43         if (!isroot(x)) relax(fa[x]);
     44         pushdown(x);
     45     }
     46     void rotate(int x){
     47         int y=fa[x],d=which(x),dd=which(y);
     48         if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
     49         fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
     50         fa[y]=x,son[x][d^1]=y,update(y);
     51     }
     52     void splay(int x){
     53         relax(x);
     54         while (!isroot(x)){
     55             if (isroot(fa[x])) rotate(x);
     56             else if (which(x)==which(fa[x])) rotate(fa[x]),rotate(x);
     57             else rotate(x),rotate(x);
     58         }
     59         update(x);
     60     }
     61     void access(int x){for (int p=0;x;x=fa[x]) splay(x),son[x][1]=p,p=x,update(x);}
     62     void make_root(int x){access(x),splay(x),rev[x]^=1;}
     63     void link(int u,int v){make_root(u),fa[u]=v;}
     64     void cut(int u,int v){make_root(u),access(v),splay(v),son[v][0]=fa[u]=0,update(v);}
     65     int find_root(int x){
     66         access(x),splay(x);
     67         while (1){
     68             pushdown(x);
     69             if (son[x][0]) x=son[x][0];
     70             else return x;
     71         }
     72     }
     73     void split(int u,int v){make_root(u),access(v),splay(v);}
     74     int query(int u,int v){split(u,v);return smax_id[v];}
     75 }lct;
     76 int main(){
     77     read(n),read(k),read(m);
     78     for (int u,v,i=1;i<=m;i++){
     79         read(u),read(v); if (u>v) swap(u,v);
     80         vec[u].push_back(mp(v,i)),wi[i][0]=u,wi[i][1]=v;
     81     }
     82     for (int i=1;i<=n;i++) val[i]=0,lct.update(i);
     83     for (int i=1;i<=m;i++) val[n+i]=wi[i][1],lct.update(n+i);
     84     read(q);
     85     for (int l,r,i=1;i<=q;i++){
     86         read(l),read(r);
     87         a[l].push_back(mp(r,i));
     88     }
     89     for (int i=n;i>=1;i--){
     90         for (int u,v,j=0;j<vec[i].size();j++){
     91             int x=vec[i][j].second;
     92             u=wi[x][0],v=wi[x][1];
     93             if (lct.find_root(u)!=lct.find_root(v)) lct.link(u,x+n),lct.link(v,x+n),t.insert(v,1);
     94             else{
     95                 int y=lct.query(u,v)-n;
     96                 if (wi[y][1]>wi[x][1]){
     97                     t.insert(wi[y][1],-1);
     98                     t.insert(wi[x][1],1);
     99                     lct.cut(y+n,wi[y][0]),lct.cut(y+n,wi[y][1]);
    100                     lct.link(x+n,u),lct.link(x+n,v);
    101                 }
    102             }
    103         }
    104         for (int j=0;j<(int)a[i].size();j++){
    105             int x=a[i][j].first;
    106             ans[a[i][j].second]=x-i+1-t.query(x);
    107         }
    108     }
    109     for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    110     return 0;
    111 }
    View Code

      题目大意:给n个点,m条边,然后q个询问,每次询问[l,r]区间中所有点带上其两两点之间的边组成的图的连通分量个数,n,q<=10^5,m<=500000;

      做法:

        做法1:分治+可持久化并查集,复杂度nlogn^3,这题过不了。

        做法2:离线处理+lct维护mst,这种做法很神奇,是我看题解的时候学到的,大致做法如下:将所有询问按照左端点排序,然后按左端点从大到小考虑,做到所有左端点为l的询问时,我们将所有边(u,v),满足u>=l,u<v的边,令其权值为v,即可参与mst的构建,这个过程去lct维护,对于一个询问l,r,答案就是r-l+1-此时mst中权值<=r的边的条数,这个用树状数组维护即可,总复杂度nlogn,十分优秀的做法。

  • 相关阅读:
    javascript:history.go()和History.back()的区别
    Web 开发] 定制IE下载对话框的按钮(打开/保存)(转)
    JavaScript 浮动定位提示效果(转)
    关于网页*静态化*及SEO问题的一些补充(转)
    httpanalyzer 结合 HttpWebRequest Post的运用
    SEO工具大全(转)
    导出excel
    Asp.NET导出Excel文件乱码解决若干方法 (转)
    关于DataBinder.Eval Eval Bind
    电脑疑似中毒
  • 原文地址:https://www.cnblogs.com/OYzx/p/6388437.html
Copyright © 2020-2023  润新知