• [校内训练20_05_26]AB


    1.给出N*M的循环平面上的k对点,每对点可以按四个方向的某个方向连成矩形,问交的最大值。

    显然可以将每一维分开考虑。对于一维问题,数轴上的某一个点能作为交的条件是惟一的,将这些条件哈希起来统计一下即可。

    O(klogk)

     1 #include<bits/stdc++.h>
     2 #define p 13131
     3 using namespace std;
     4 typedef long long int ll;
     5 typedef unsigned long long ull;
     6 const int maxn=5E5+5;
     7 int n;
     8 int X,Y;
     9 ull Hash[maxn];
    10 inline int read()
    11 {
    12     char ch=getchar();
    13     while(!isdigit(ch))ch=getchar();
    14     int s=ch-'0';ch=getchar();
    15     while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    16     return s;
    17 }
    18 struct line
    19 {
    20     int l,r;
    21 }a[maxn],b[maxn];
    22 struct pt
    23 {
    24     int x;
    25     int num,type;
    26     bool operator<(const pt&A)const
    27     {
    28         return x==A.x?type<A.type:x<A.x;
    29     }
    30 }P[maxn*4];
    31 inline void init()
    32 {
    33     Hash[0]=1;
    34     for(int i=1;i<=500000;++i)
    35         Hash[i]=Hash[i-1]*p;
    36 }
    37 inline ll solve(line*A,int len)
    38 {
    39     map<ull,int>bucket;
    40     ull now=0;
    41     int tot=0;
    42     for(int i=1;i<=n;++i)
    43     {
    44         P[++tot]=(pt){A[i].l,i,1};
    45         P[++tot]=(pt){A[i].l,0,0};
    46         P[++tot]=(pt){A[i].r,i,2};
    47         P[++tot]=(pt){A[i].r,0,0};
    48     }
    49     P[++tot]=(pt){0,0,0};
    50     P[++tot]=(pt){len,0,0};
    51     sort(P+1,P+tot+1);
    52     int last=0;
    53     for(int i=1;i<=tot;++i)
    54     {
    55         if(P[i].type==2)
    56             now-=Hash[P[i].num];
    57         else if(P[i].type==1)
    58             now+=Hash[P[i].num];
    59         else
    60         {
    61             bucket[now]+=P[i].x-last;
    62             last=P[i].x;
    63         }
    64         last=P[i].x;
    65     }
    66     int ans=0;
    67     for(map<ull,int>::iterator pt=bucket.begin();pt!=bucket.end();++pt)
    68         ans=max(ans,(*pt).second);
    69     return ans;
    70 }
    71 int main()
    72 {
    73     freopen("master.in","r",stdin);
    74     freopen("master.out","w",stdout);
    75     ios::sync_with_stdio(false);
    76     init();
    77     n=read(),X=read(),Y=read();
    78     for(int i=1;i<=n;++i)
    79         a[i].l=read(),b[i].l=read(),a[i].r=read(),b[i].r=read();
    80     cout<<solve(a,X)*solve(b,Y)<<endl;
    81     return 0;
    82 }
    View Code

    2.一个仙人掌,求$sigma_{i<j}{f(i,j)*i*j}$,其中f(i,j)表示i,j间的最小割,乘法定义为异或。

    首先将每一位分开来考虑。对于一棵树,f(i,j)显然为两点间的最小值,因此将边权从大到小插入,每次统计插入的边两端的答案即可。

    对于一个仙人掌,若要割掉一个环,那么环上最小的边一定会被选中。因此对于一个环,将边权最小的边删去,环上其余的边的边权加上其边权即可。

    O(nlogw)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long int ll;
      4 const int maxn=2E5+5;
      5 int n,m;
      6 int size,head[maxn];
      7 struct edge
      8 {
      9     int to,next,w;
     10 }E[maxn*2];
     11 int tot,top;
     12 inline int read()
     13 {
     14     char ch=getchar();
     15     while(!isdigit(ch))ch=getchar();
     16     int s=ch-'0';ch=getchar();
     17     while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
     18     return s;
     19 }
     20 struct pt
     21 {
     22     int x,y,w,id;
     23     pt(int a=0,int b=0,int c=0,int d=0):x(a),y(b),w(c),id(d){}
     24     inline bool operator<(const pt&A)const
     25     {
     26         return w>A.w;
     27     }
     28 }wait[maxn*2],S[maxn*2];
     29 inline void add(int u,int v,int w)
     30 {
     31     E[++size].to=v;
     32     E[size].next=head[u];
     33     E[size].w=w;
     34     head[u]=size;
     35 }
     36 bool vis[maxn],in[maxn],used[maxn*2];
     37 void dfs(int u,int F)
     38 {
     39     in[u]=vis[u]=1;
     40     for(int i=head[u];i;i=E[i].next)
     41     {
     42         int v=E[i].to;
     43         if(v==F)
     44             continue;
     45         if(vis[v])
     46         {
     47             if(in[v])
     48             {
     49                 S[++top]=pt(u,v,E[i].w,i);
     50                 int minn=INT_MAX,pos=0;
     51                 for(int j=top;;--j)
     52                 {
     53                     if(S[j].w<minn)
     54                         minn=S[j].w,pos=j;
     55                     used[S[j].id]=1;
     56                     if(S[j].x==v)
     57                         break;
     58                 }
     59                 for(int j=top;;--j)
     60                 {
     61                     if(j!=pos)
     62                         wait[++tot]=pt(S[j].x,S[j].y,S[j].w+minn);
     63                     --top;
     64                     if(S[j].x==v)
     65                         break;
     66                 }
     67             }
     68             continue;
     69         }
     70         else
     71         {
     72             S[++top]=pt(u,v,E[i].w,i);
     73             dfs(v,u);
     74             if(!used[i])
     75                 wait[++tot]=pt(u,v,E[i].w),--top;
     76         }
     77     }
     78     in[u]=0;
     79 }
     80 int sum0[maxn][22],sum1[maxn][22];
     81 struct UFO
     82 {
     83     int fa[maxn];
     84     inline void clear()
     85     {
     86         for(int i=0;i<=n;++i)
     87             fa[i]=i;
     88     }
     89     inline int find(int x)
     90     {
     91         return fa[x]==x?x:fa[x]=find(fa[x]);
     92     }
     93     inline void merge(int x,int y)
     94     {
     95         fa[find(x)]=find(y);
     96     }
     97 }U;
     98 inline ll get()
     99 {
    100     U.clear();
    101     memset(sum0,0,sizeof(sum0));
    102     memset(sum1,0,sizeof(sum1));
    103     for(int d=0;d<21;++d)
    104         for(int i=1;i<=n;++i)
    105             if(i&(1<<d))
    106                 sum1[i][d]=1;
    107             else
    108                 sum0[i][d]=1;
    109     ll s=0;
    110     for(int i=1;i<=tot;++i)
    111     {
    112         int x=wait[i].x,y=wait[i].y;
    113         x=U.find(x),y=U.find(y);
    114         for(int d=0;d<21;++d)
    115         {
    116             if(wait[i].w&(1<<d))
    117                 s+=((ll)sum0[x][d]*sum0[y][d]+(ll)sum1[x][d]*sum1[y][d])<<d;
    118             else
    119                 s+=((ll)sum0[x][d]*sum1[y][d]+(ll)sum1[x][d]*sum0[y][d])<<d;
    120             sum0[x][d]+=sum0[y][d];
    121             sum1[x][d]+=sum1[y][d];
    122         }
    123         U.merge(y,x);
    124     }
    125     return s;
    126 }
    127 inline void solve()
    128 {
    129     memset(vis,0,sizeof(vis));
    130     memset(head,0,sizeof(head));
    131     memset(used,0,sizeof(used));
    132     size=0;
    133     n=read(),m=read();
    134     for(int i=1;i<=m;++i)
    135     {
    136         int x=read(),y=read(),z=read();
    137         add(x,y,z);
    138         add(y,x,z);
    139     }
    140     top=tot=0;
    141     dfs(1,0);
    142 //    cout<<tot<<endl;
    143 //    for(int i=1;i<=tot;++i)
    144 //        cout<<"--- "<<wait[i].x<<" "<<wait[i].y<<" "<<wait[i].w<<endl;
    145 //    assert(tot+1==n);
    146     sort(wait+1,wait+tot+1);
    147     ll ans=0;
    148     cout<<get()<<endl;
    149 }
    150 int main()
    151 {
    152     freopen("okfly.in","r",stdin);
    153     freopen("okfly.out","w",stdout);
    154     ios::sync_with_stdio(false);
    155     int T=read();
    156     while(T--)
    157         solve();
    158     return 0;
    159 }
    View Code
  • 相关阅读:
    BZOJ4754 JSOI2016独特的树叶(哈希)
    锦标赛游戏 解题报告
    nowcoder OI 周赛 最后的晚餐(dinner) 解题报告
    Prufer序列
    牛客网 Wannafly挑战赛27 蓝魔法师
    替罪羊树板子
    AT1984 Wide Swap
    洛谷 P1829 [国家集训队]Crash的数字表格 / JZPTAB 解题报告
    CF858F Wizard's Tour 解题报告
    OI中组合数的若干求法与CRT
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/12963018.html
Copyright © 2020-2023  润新知