1. 程式人生 > >Codeforces Round #535 (Div. 3)

Codeforces Round #535 (Div. 3)

swa clu blog stream break Edito pri tdi edge

其實也是近一個月之前的一場cf了,div3真是吼啊。今天忽然想起來補完剩下的題。

前五道暴力模擬什麽的略過不寫了。

E2 Array and Segments (Hard version)

題意:給出大小為n的數組a,m個區間。你可以決定每個區間是否進行操作(對區間內的數全部減1),給出任一方案使得數組最大值與最小值的差最大。n<=1e5,m<=300

E2和E1的區別只有數據範圍,E1可以暴力枚舉選擇每個數作為最小值的情況(將包含最小值的區間全部進行操作),每次更新答案,O(n2m)。

E2可以在此基礎上進行改進。線段樹進行區間操作查詢最大值的優化比較好想。然後發現這個m很小…從m入手發現可以用所有區間的端點可以將數組分成不超過601段,在每一段內的i我們按照如上原則選擇的操作是相同的,由此可以批量處理降低時間復雜度。

(然而代碼寫的就非常不優雅,我自己看完都想說這是什麽辣雞…甚至一年半沒寫線段樹了吧。有機會可能會看看官方Tutorial裏的方法重寫。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define Max(a,b) (a>b?a:b)
#define N 100005
#define INF 0x3f3f3f3f
using
namespace std; int read() { int x=0,f=1; char c=getchar(); while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } int n,m,a[N],l[303],r[303]; int seg[606],ans=0; vector<int>A,cp; struct Node {
int l,r,maxn,lazy; }t[N*4]; void build(int idx,int l,int r) { t[idx].l=l,t[idx].r=r; if(l==r){t[idx].maxn=a[l],t[idx].lazy=0;return;} int mid=(l+r)>>1; build(idx<<1,l,mid),build(idx<<1|1,mid+1,r); t[idx].maxn=Max(t[idx<<1].maxn,t[idx<<1|1].maxn); } void pushdown(int idx) { if(t[idx].lazy&&t[idx].l!=t[idx].r) { int lz=t[idx].lazy; t[idx].lazy=0; t[idx<<1].lazy+=lz,t[idx<<1|1].lazy+=lz; t[idx<<1].maxn+=lz,t[idx<<1|1].maxn+=lz; } } void add(int idx,int l,int r,int w) { if(l<=t[idx].l&&r>=t[idx].r) { t[idx].maxn+=w,t[idx].lazy+=w; return; } pushdown(idx); int mid=(t[idx].l+t[idx].r)>>1; if(r<=mid)add(idx<<1,l,r,w); else if(l>mid)add(idx<<1|1,l,r,w); else add(idx<<1,l,r,w),add(idx<<1|1,l,r,w); t[idx].maxn=Max(t[idx<<1].maxn,t[idx<<1|1].maxn); } int main() { n=read(),m=read(); for(int i=1;i<=n;i++)a[i]=read(); build(1,1,n); for(int i=1;i<=m;i++) { l[i]=read(),r[i]=read(); seg[i*2-1]=l[i],seg[i*2]=r[i]; } sort(seg+1,seg+2*m+1),seg[0]=0; int cnt=unique(seg+1,seg+2*m+1)-seg-1; seg[cnt+1]=INF; int now=0,f; for(int i=1;i<=n;i++) { if(i==seg[now]||(i>seg[now]&&i==seg[now+1])) { f=0,cp.clear(); if(i==seg[now+1])now++; for(int j=1;j<=m;j++) { if(l[j]<=i&&r[j]>=i) f++,add(1,l[j],r[j],-1),cp.push_back(j); } } else if(i>seg[now]) { now++,f=0,cp.clear(); for(int j=1;j<=m;j++) { if(l[j]<=seg[now-1]+1&&r[j]>=seg[now]-1) f++,add(1,l[j],r[j],-1),cp.push_back(j); } } int minnum=a[i]-f; if(t[1].maxn-minnum>ans) { ans=t[1].maxn-minnum; A=cp; } if(i==seg[now]-1||i==seg[now]) { for(int j=0;j<cp.size();j++) add(1,l[cp[j]],r[cp[j]],1); } } printf("%d\n%d\n",ans,A.size()); for(int i=0;i<A.size();i++) printf("%d ",A[i]); return 0; }
F. MST Unification 題意:給出一個帶權無向圖,你可以增加任意邊的邊權使得最小生成樹唯一。求所增加的邊權總和的最小值。 先用kruskal跑出一個MST,在這個MST上倍增LCA。對於每一條未被加入當前MST的邊進行判斷,如果其邊權與u,v間路徑上的最大邊權相等,則這條邊可以起替代作用,需要給權值+1。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Max(a,b) (a>b?a:b)
#define N 200005
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    return x*f;
}
int n,m,head[N],cnt=0,father1[N],dep[N],p[N][20],mlen[N][20];
bool used[N];
struct Node1
{
    int u,v,w;
}Edges1[N];
bool operator < (Node1 A,Node1 B){return A.w<B.w;}
struct Node2
{
    int nxt,to,w;
}Edges2[N*2];
int findf(int x)
{return (father1[x]==x)?x:(father1[x]=findf(father1[x]));}
void addedge(int u,int v,int w)
{
    Edges2[++cnt].nxt=head[u];
    head[u]=cnt;
    Edges2[cnt].to=v,Edges2[cnt].w=w;
}
void dfs(int u)
{
    for(int i=head[u];~i;i=Edges2[i].nxt)
    {
        int v=Edges2[i].to;
        if(v==p[u][0])continue;
        p[v][0]=u,dep[v]=dep[u]+1,mlen[v][0]=Edges2[i].w;
        dfs(v);
    }
}
void init()
{
    for(int i=1;(1<<i)<=n;i++)
    for(int j=1;j<=n;j++)
    p[j][i]=p[p[j][i-1]][i-1],mlen[j][i]=max(mlen[j][i-1],mlen[p[j][i-1]][i-1]);
}
int lca(int x,int y)
{
    int res=0;
    if(dep[x]>dep[y])swap(x,y);
    int f=dep[y]-dep[x];
    for(int i=0;(1<<i)<=f;i++)
    if(f&(1<<i))res=Max(res,mlen[y][i]),y=p[y][i];
    if(x!=y)
    {
        for(int i=(int)log2(n);i>=0;i--)
        if(p[x][i]!=p[y][i])res=Max(res,mlen[x][i]),res=Max(res,mlen[y][i]),x=p[x][i],y=p[y][i];
        res=Max(res,mlen[x][0]),res=Max(res,mlen[y][0]),x=p[x][0];
    }
    return res;
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(dep,0,sizeof(dep));
    memset(used,0,sizeof(used));
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    Edges1[i].u=read(),Edges1[i].v=read(),Edges1[i].w=read();
    sort(Edges1+1,Edges1+1+m);
    for(int i=1;i<=n;i++)father1[i]=i;
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        int fu=findf(Edges1[i].u),fv=findf(Edges1[i].v);
        if(fu!=fv)
        {
            cnt++;
            addedge(Edges1[i].u,Edges1[i].v,Edges1[i].w);
            addedge(Edges1[i].v,Edges1[i].u,Edges1[i].w);
            used[i]=1;father1[fu]=fv; 
        }
        if(cnt==n-1)break;
    }
    dep[1]=mlen[1][0]=0;p[1][0]=1;
    dfs(1),init();
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        if(used[i])continue;
        int u=Edges1[i].u,v=Edges1[i].v;
        int maxlen=lca(u,v);
        if(maxlen==Edges1[i].w)ans++;
    }
    printf("%d\n",ans);
    return 0;
} 

Codeforces Round #535 (Div. 3)