HNOI2018

d1t1[HNOI/AHOI2018]寻宝游戏

感觉很神,反正我完全没想到

分开考虑每一位,对于每一位i计算一个二进制数b[i],

对于第i位,从后往前第j个数这一位是1,那么b[i]^=(1<<j)

对于操作,从后往前考虑每个数前面的符号,把&看成1,|看成0

把一个操作序列看成一个二进制数c

发现|0和&1等于无影响,一个操作序列的最后一个|1或者&0决定结果的值

那么对于第i位,要使这一位为1,必须满足c<b[i]

(这一位是1,则要选择一个b[i]中是1的位置取|,并将它之前的所有操作任意取,之后的操作有唯一取法,相当于将二进制位中某个1变成0,高位不变,低位任意取,最后得到c<b[i])

那么将b从大到小排序,对于每个询问,首先满足找到最靠左的0必须在1后面,然后最靠左的0的位置为pos,答案为b[pos-1]-b[pos]

要取模,一开始傻乎乎地在那里写高精...

 1 //Achen
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<vector>
 7 #include<cstdio>
 8 #include<queue>
 9 #include<cmath>
10 #define For(i,a,b) for(int i=(a);i<=(b);i++)
11 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
12 const int N=5007,mod=1e9+7;
13 typedef long long LL;
14 typedef double db;
15 using namespace std;
16 const LL mxup=(1LL<<58);
17 int n,m,q,sa[N],rak[N],L;
18 LL ans[N];
19 char s[1007][N],ss[N];
20 
21 template<typename T>void read(T &x)  {
22     char ch=getchar(); x=0; T f=1;
23     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
24     if(ch=='-') f=-1,ch=getchar();
25     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
26 }
27 
28 bool cmp(const int &A,const int &B) {
29     Rep(i,n,1) {
30         if(s[i][A]!=s[i][B]) return s[i][A]>s[i][B];
31     } return 1;
32 }
33 
34 void pre() {
35     For(i,0,m) 
36         Rep(j,n,1) {
37             int x=i==0?1:s[j][i]-'0';
38             ans[i]=((ans[i]<<1)%mod+x)%mod;
39         }
40     ans[0]=(ans[0]+1)%mod;
41 }
42 
43 //#define DEBUG
44 int main() {
45 #ifdef DEBUG
46     freopen("hunt.in","r",stdin);
47     freopen("hunt.out","w",stdout);
48 #endif
49     read(n); read(m); read(q);
50     For(i,1,n) scanf("%s",s[i]+1);
51     For(i,1,m) sa[i]=i;
52     sort(sa+1,sa+m+1,cmp);
53     For(i,1,m) rak[sa[i]]=i;
54     pre();
55     while(q--) {
56         int ll=0,rr=m+1;
57         scanf("%s",ss+1);
58         For(i,1,m) {
59             int x; x=ss[i]-'0';
60             if(x==1) ll=max(ll,rak[i]); 
61             else if(!rr||rr>rak[i]) rr=rak[i];
62         }
63         if(rr<ll) puts("0");
64         else {
65             LL rs=(rr==m+1?ans[sa[rr-1]]:(ans[sa[rr-1]]-ans[sa[rr]]+mod)%mod);
66             printf("%lld
",rs);
67         }
68     }
69     return 0;
70 }
71 /*
72 5 5 1
73 01110
74 11011
75 10000
76 01010
77 00100
78 00100
79 */
View Code

d1t2[HNOI/AHOI2018]转盘

贪心.发现一定有一种最优答案是在某个起点待着不动一会,然后一路走下去

考虑如果答案是走了很多圈,最后一个取的点为x,那么从最后时刻从x往前走一圈,一路上所有东西肯定都是已经出现了的,把游戏倒过来,就是从x往前走,在每个物品消失前取到它,那么最优策略一定是从x一步不停地走下去,那么正过来也是一样.

把原序列倍长,答案就等于 

$ans=min_{i=1}^n(max_{j=i}^{2*n}T[j]-(j-i)+n-1)$

$设A[i]=T[i]-i$

$ans=min_{i=1}^n(max_{j=i}^{2*n}A[j]+i)+n+1$

维护和楼房重建很像.

用线段树维护答案,线段树上分别维护A[i]的最大值,和在l~r这段区间中来算(即n=r,i=l~n),i在l~mid中的答案的最小值

支持询问qry(x,l,r,suf)表示i在l,r这段去就,A[i]和suf取max后的答案,那么修改时可以调用qry在两个log的时间里更新线段树里的值

注意询问时直接输出线段树中根的答案,而不是调用qry(suf会出问题),

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=200007;
typedef long long LL; 
typedef double db;
using namespace std;
int n,m,p,T[N],A[N],ans;

template<typename T> void read(T &x) {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define lc x<<1
#define rc ((x<<1)|1)
#define mid ((l+r)>>1)
int mx[N<<2],sg[N<<2];
int qry(int x,int l,int r,int suf) {
    if(l==r) return max(suf,mx[x])+l;
    if(mx[rc]>=suf) return min(sg[x],qry(rc,mid+1,r,suf));
    else return min(qry(lc,l,mid,suf),suf+mid+1);
}

void update(int x,int l,int r) {
    mx[x]=max(mx[lc],mx[rc]);
    sg[x]=qry(lc,l,mid,mx[rc]);
}

void change(int x,int l,int r,int pos) {
    if(l==r) {
        mx[x]=A[l]; sg[x]=A[l]+l; return;
    }
    if(pos<=mid) change(lc,l,mid,pos);
    else change(rc,mid+1,r,pos);
    update(x,l,r);
}

void build(int x,int l,int r) {
    if(l==r) { mx[x]=A[l]; sg[x]=A[l]+l; return; }
    build(lc,l,mid); build(rc,mid+1,r);
    update(x,l,r);
}

//#define DEBUG
int main() {
#ifdef DEBUG
    freopen("circle.in","r",stdin);
    freopen("circle.out","w",stdout);
#endif
    read(n); read(m); read(p);
    For(i,1,n) { 
        read(T[i]); A[i]=T[i]-i; 
        T[i+n]=T[i]; A[i+n]=T[i+n]-(i+n);    
    }
    build(1,1,n*2);
    ans=sg[1]+n-1;
    printf("%d
",ans);
    For(i,1,m) {
        int x,y;
        read(x); read(y);
        if(p) x^=ans,y^=ans;
        T[x]=y; A[x]=T[x]-x;
        change(1,1,n*2,x);
        T[x+n]=y; A[x+n]=T[x+n]-(x+n);
        change(1,1,n*2,x+n);
        ans=sg[1]+n-1;
        printf("%d
",ans);
    }
    return 0;
}
View Code

d1t3[HNOI/AHOI2018]毒瘤

如果给出的一棵树,可以直接树dp,时间复杂度O(n)

发现非树边很少,可以枚举非树边上的点的状态,然后dp,时间复杂度为2^d*n(只用枚举每条非树边中一个点的状态)

考虑优化这个算法,发现每次树dp只有非树边上的点有影响,重复计算了很多没有必要的过程

那么把非树边拿出来建虚树,每次在虚树上dp

先对原树dp一次求出在虚树上dp要用到的系数

设g[x][0/1]表示常数,即x的那些没有任何关键点的儿子的贡献.

k[x][0/1][0/1]表示我对于我下面(包括我)第一个关键点的转移系数

即(设我下面第一个关键点为w) 

f[x][0]= k[x][0][0]*f[w][0]+k[x][0][1]*f[w][1];

f[x][1]= k[x][1][0]*f[w][0]+k[x][1][1]*f[w][1];

边界为若我为关键点,

k[x][0][0]=1,k[x][0][1]=0;

k[x][1][0]=0,k[x][1][1]=1;

dp出k和g,就可以在虚树上转移了

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
const int N=200007,p=998244353;
typedef long long LL; 
typedef double db;
using namespace std;
int n,m,eu[N],ev[N],tot;

template<typename T> void read(T &x) {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

int ecnt,fir[N],nxt[N<<1],to[N<<1];
void add(int u,int v) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}

int sz[N],is[N],vis[N];
void dfs(int x,int fa) {
    vis[x]=1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        if(!vis[to[i]]) {
            dfs(to[i],x);
            sz[x]+=sz[to[i]];
        }
        else {
            is[x]=1;
            if(to[i]<x) eu[++tot]=x,ev[tot]=to[i];
        }
    }
    is[x]=(is[x]||sz[x]>=2);
    sz[x]=(sz[x]||is[x]);
}

struct pt {
    LL a,b;
    pt(){}
    pt(int a,int b):a(a),b(b){}
    friend pt operator +(const pt&A,const pt&B) {
        return pt((A.a+B.a)%p,(A.b+B.b)%p);
    }
    friend pt operator *(const pt&A,const LL&B) {
        return  pt(A.a*B%p,A.b*B%p);
    }
}k[N][2];

struct edge {
    int u,v,nx;
    pt x,y;
    edge(){}
    edge(int u,int v,pt x,pt y,int nx):u(u),v(v),x(x),y(y),nx(nx){}
}e[N];

int fi[N],ec;
void ADD(int u,int v,pt x,pt y) {
    e[++ec]=edge(u,v,x,y,fi[u]); fi[u]=ec;
}

LL g[N][2],bx[N][2],f[N][2],ans;
int pre(int x,int fa) {
    vis[x]=1;
    g[x][0]=g[x][1]=1;
    int rs=0;
    if(x==2874) {
        int debug=1;
    }
    for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
        int w=pre(to[i],x); if(!rs) rs=w;
        if(!w) {
            g[x][0]=g[x][0]*((g[to[i]][0]+g[to[i]][1])%p)%p;
            g[x][1]=g[x][1]*g[to[i]][0]%p;
        }
        else if(is[x]) ADD(x,w,k[to[i]][0]+k[to[i]][1],k[to[i]][0]);
        else k[x][0]=k[to[i]][0]+k[to[i]][1],k[x][1]=k[to[i]][0];
    } 
    if(is[x]) k[x][0]=pt(1,0),k[x][1]=pt(0,1);
    else k[x][0]=k[x][0]*g[x][0],k[x][1]=k[x][1]*g[x][1];
    if(is[x]) rs=x;
    return rs;
}

void dp(int x) {
    f[x][0]=bx[x][1]?0:g[x][0];
    f[x][1]=bx[x][0]?0:g[x][1];
    for(int i=fi[x];i;i=e[i].nx) {
        int v=e[i].v; 
        pt a=e[i].x,b=e[i].y;
        dp(v);
        f[x][0]=(f[x][0]*(a.a*f[v][0]%p+a.b*f[v][1]%p))%p;
        f[x][1]=(f[x][1]*(b.a*f[v][0]%p+b.b*f[v][1]%p))%p;
    }
}

//#define DEBUG
int main() {
#ifdef DEBUG
    freopen("duliu.in","r",stdin);
    freopen("duliu.out","w",stdout);
#endif
    read(n); read(m);
    For(i,1,m) {
        int u,v;
        read(u); read(v);
        add(u,v);    
    }
    dfs(1,0); is[1]=1;
    memset(vis,0,sizeof(vis));
    pre(1,0);
    int nn=(1<<tot)-1;
    For(i,0,nn) {
        For(j,1,tot) { 
            if(i&(1<<j-1)) {
                bx[eu[j]][1]=1; bx[ev[j]][0]=1;
            }
            else bx[eu[j]][0]=1;
        }
        dp(1);
        ans=((ans+f[1][0])%p+f[1][1])%p;
        For(j,1,tot) { 
            if(i&(1<<j-1)) {
                bx[eu[j]][1]=0; bx[ev[j]][0]=0;
            }
            else bx[eu[j]][0]=0;
        }
    }
    printf("%lld
",ans);
    return 0;
}
/*
12 17
12 3
12 5
11 12
7 5
5 10
1 5
5 8
8 7
11 9
3 6
10 1
1 9
1 7
12 4
2 9
11 2
7 3
*/
View Code

d2t1游戏

sxy的做法:

  一个点能走到的是一段区间,记为l[x],r[x]

  若一段路的钥匙在左端点及左边,那么只能从左走到右,从左到右连单向边.

  若钥匙在右端点及右边,那么只能从右走到左,单向边

  否则连双向边.预处理出这些边都能走的情况下左右最远走到哪里,记为ld,rd

  然后从左到右计算l,r,

  1.若我可以到左边,且钥匙在我这里或者不需要钥匙,那么l[x]=l[x-1],r[x]=r[x-1]

  2.若我到不了左边,在x~rd[x]中二分一个位置pos,使这从x到pos这一段的每一个位置的钥匙都在从x到它之间,l[x]=x,r[x]=pos

  3.我能到左边,拿不到钥匙.先和2一样二分一个pos,看在这一段中能不能拿到左边的钥匙,l[x]拓展到l[x-1],拿到这一段钥匙后继续往右边二分,然后再试图向左拓展

    发现每次向左拓展的点一定是之前未拓展到的,那么每条向左的边最多会使我向左拓展一次,每次向右拓展复杂的是一个log,总复杂的nlogn

我的一个及其蠢的做法:

  发现如果从x能走到y(假使x在y左边,右边同理),设x到y的路径上最靠左的钥匙位置在z,走过的路径即为z,x,y这一段

  这一段路径要能走需要满足,x到y路径上任意一个点a,它的钥匙在的地方b,从x到b的每个点的钥匙必须在它右边且在a左边

  那么对于每个点x,它的钥匙在它左边的y,可以二分一个最靠右的z使y到z的路径上所有点的钥匙都在自己的右边且在x的左边,记录这个最靠右的位置为rans[x]

  那么x能走到y需要满足从x到y的rans都大于x

  对于rans可以用线段树记录所有点钥匙所在的位置,在线段树上二分,求出rans后第二个问题可以用线段树解决.

  同理考虑左边的lans

  x在y右边的情况同理

  时间复杂度nlogn,然而常数巨大..本机卡常卡过了,洛谷t了两个点

  1 // luogu-judger-enable-o2
  2 //Achen
  3 #include<algorithm>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<vector>
  8 #include<cstdio>
  9 #include<queue>
 10 #include<cmath>
 11 #include<set>
 12 #define For(i,a,b) for(register int i=(a);i<=(b);i++)
 13 #define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
 14 const int N=1e6+7;
 15 typedef long long LL; 
 16 typedef double db;
 17 using namespace std;
 18 int n,m,q,yl[N];
 19 
 20 template<typename T> void read(T &x) {
 21     char ch=getchar(); x=0; T f=1;
 22     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
 23     if(ch=='-') f=-1,ch=getchar();
 24     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
 25 }
 26 
 27 #define lc x<<1
 28 #define rc ((x<<1)|1)
 29 #define mid ((l+r)>>1)
 30 int mx[N<<2],mi[N<<2];
 31 inline void build(int x,int l,int r) {
 32     if(l==r) { 
 33         mx[x]=mi[x]=yl[l]; 
 34         if(yl[l]==0) mx[x]=0,mi[x]=n+1; 
 35         return; 
 36     }
 37     build(lc,l,mid); build(rc,mid+1,r);
 38     mx[x]=max(mx[lc],mx[rc]);
 39     mi[x]=min(mi[lc],mi[rc]);
 40 }
 41 
 42 inline int qryl(int x,int l,int r,int ql,int qr,int v) {
 43     if(l>=ql&&r<=qr) {
 44         if(mx[x]<=v) return r;
 45         if(l==r) return 0;
 46         if(mx[lc]<=v) {
 47             int rs=qryl(rc,mid+1,r,ql,qr,v);
 48             if(!rs) rs=mid;
 49             return rs;
 50         }
 51         else return qryl(lc,l,mid,ql,qr,v);
 52     }
 53     int rs=0;
 54     if(ql>mid) return qryl(rc,mid+1,r,ql,qr,v);
 55     if(qr<=mid) return qryl(lc,l,mid,ql,qr,v);
 56     else {
 57         rs=qryl(lc,l,mid,ql,qr,v);
 58         int rs2=0;
 59         if(rs==mid) rs2=qryl(rc,mid+1,r,ql,qr,v);
 60         if(rs2) rs=rs2;
 61         return rs;
 62     }  
 63 }
 64 
 65 inline int qryr(int x,int l,int r,int ql,int qr,int v) {
 66     if(l>=ql&&r<=qr) {
 67         if(mi[x]>=v) return l;
 68         if(l==r) return 0;
 69         if(mi[rc]>=v) {
 70             int rs=qryr(lc,l,mid,ql,qr,v);
 71             if(!rs) rs=mid+1;
 72             return rs;
 73         }
 74         else return qryr(rc,mid+1,r,ql,qr,v);
 75     }
 76     int rs=0;
 77     if(ql>mid) return qryr(rc,mid+1,r,ql,qr,v);
 78     if(qr<=mid) return qryr(lc,l,mid,ql,qr,v);
 79     else {
 80         rs=qryr(rc,mid+1,r,ql,qr,v);
 81         int rs2=0;
 82         if(rs==mid+1) rs2=qryr(lc,l,mid,ql,qr,v);
 83         if(rs2) rs=rs2;
 84         return rs;    
 85     }
 86 }
 87 
 88 int lans[N],rans[N];
 89 int sgmi[N<<2],sgmx[N<<2];
 90 inline void build2(int x,int l,int r) {
 91     if(l==r) { sgmi[x]=rans[l]; sgmx[x]=lans[l]; return; }
 92     build2(lc,l,mid); build2(rc,mid+1,r);
 93     sgmi[x]=min(sgmi[lc],sgmi[rc]);    
 94     sgmx[x]=max(sgmx[lc],sgmx[rc]);
 95 }
 96 
 97 inline int qrymi(int x,int l,int r,int ql,int qr,int sg[]) {
 98     if(l>=ql&&r<=qr) return sg[x];
 99     if(qr<=mid) return qrymi(lc,l,mid,ql,qr,sg);
100     if(ql>mid) return qrymi(rc,mid+1,r,ql,qr,sg);
101     return min(qrymi(lc,l,mid,ql,qr,sg),qrymi(rc,mid+1,r,ql,qr,sg));
102 }
103 
104 inline int qrymx(int x,int l,int r,int ql,int qr,int sg[]) {
105     if(l>=ql&&r<=qr) return sg[x];
106     if(qr<=mid) return qrymx(lc,l,mid,ql,qr,sg);
107     if(ql>mid) return qrymx(rc,mid+1,r,ql,qr,sg);
108     return max(qrymx(lc,l,mid,ql,qr,sg),qrymx(rc,mid+1,r,ql,qr,sg));
109 }
110 
111 //#define DEBUG
112 int main() {
113 #ifdef DEBUG
114     freopen("game.in","r",stdin);
115     freopen("game.out","w",stdout);
116 #endif
117     read(n); read(m); read(q);
118     For(i,1,m) {
119         int x,y;
120         read(x); read(y);
121         yl[x]=y;
122     }
123     build(1,1,n-1);
124     For(i,1,n) {
125         if(yl[i]==0) {
126             lans[i]=0;
127             rans[i]=n+1;
128         }
129         else {
130             if(yl[i]>i) 
131                 lans[i]=qryr(1,1,n-1,1,yl[i]-1,i+1);
132             else lans[i]=n+1;
133             if(yl[i]<=i) 
134                 rans[i]=qryl(1,1,n-1,yl[i],n,i);
135             else rans[i]=0;
136         }
137     }
138     build2(1,1,n-1);
139     For(i,1,q) {
140         int x,y;
141         read(x); read(y);
142         if(x==y) puts("YES");
143         else if(x<=y) {
144             int z=qrymi(1,1,n-1,x,y-1,mi);
145             int tp1=qrymi(1,1,n-1,x,y-1,sgmi);
146             int tp2=z>x-1?x:qrymx(1,1,n-1,z,x-1,sgmx);
147             if(tp1>=max(1,x-1)&&tp2<=min(n,x+1)) puts("YES");
148             else puts("NO");
149         }
150         else {
151             int z=qrymx(1,1,n-1,y,x-1,mx);
152             int tp2=qrymx(1,1,n-1,y,x-1,sgmx);
153             int tp1=z-1<x?x:qrymi(1,1,n-1,x,z-1,sgmi);
154             if(tp1>=max(1,x-1)&&tp2<=min(n,x+1)) puts("YES");
155             else puts("NO");
156         }
157     }
158     return 0;
159 }
View Code

正解:按sxy的做法把图建出来后,按拓扑序拓展,似乎就可以直接做到O(n)了

d2t2排列

读题读好久..转换过来就是,给一棵树,父亲必须比儿子先选,选出来的序列记为p,答案为i*p[i]的和

贪心

考虑合并两段区间a,b,区间内已经合并好了,若a放在b前面更优,则说明len[a]*val[b]>len[b]*val[a]

即len[a]/val[a]>len[b]/val[b];

那么优先队列存每段区间的len和val,每次取出队首和父亲合并即可.

 1 //Achen
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<vector>
 7 #include<cstdio>
 8 #include<queue>
 9 #include<cmath>
10 #include<set>
11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
13 const int N=1000007;
14 typedef long long LL; 
15 typedef double db;
16 using namespace std;
17 int n,a[N],w[N],fa[N],len[N];
18 LL sum[N];
19 
20 template<typename T> void read(T &x) {
21     char ch=getchar(); x=0; T f=1;
22     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
23     if(ch=='-') f=-1,ch=getchar();
24     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
25 }
26 
27 struct node {
28     int x,sz; LL sum;
29     node(int x,int sz,LL sum):x(x),sz(sz),sum(sum){}
30     friend bool operator <(const node&A,const node&B) {
31         return A.sz*B.sum<B.sz*A.sum;
32     }
33 };
34 
35 int ecnt,fir[N],nxt[N],to[N],in[N];
36 void add(int u,int v) {
37     nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; in[v]++;
38 }
39 
40 queue<int>q;
41 LL tpsort() {
42     int tot=0;
43     For(i,1,n) if(!in[i]) q.push(i);
44     while(!q.empty()) {
45         int x=q.front();
46         q.pop();
47         tot++;
48         for(int i=fir[x];i;i=nxt[i]) {
49             in[to[i]]--;
50             if(!in[to[i]]) q.push(to[i]);
51         }
52     } 
53     if(tot!=n) return -1;
54     return 1;
55 }
56 
57 int f[N];
58 int find(int x) { return x==f[x]?f[x]:f[x]=find(f[x]); }
59 
60 priority_queue<node>que;
61 LL solve() {
62     LL rs=0;
63     For(i,1,n) rs+=w[i],f[i]=i;
64     while(!que.empty()) {
65         node tp=que.top();
66         que.pop(); 
67         if(tp.sz!=len[tp.x]) continue;
68         int F=find(fa[tp.x]);
69         rs+=sum[tp.x]*len[F];
70         sum[F]+=sum[tp.x]; 
71         len[F]+=len[tp.x];
72         f[tp.x]=F;
73         if(F) que.push(node(F,len[F],sum[F])); 
74     }
75     return rs;
76 }
77 
78 //#define DEBUG
79 int main() {
80 #ifdef DEBUG
81     freopen("perm.in","r",stdin);
82     freopen("perm.out","w",stdout);
83 #endif
84     read(n);
85     For(i,1,n) {
86         read(a[i]);
87         if(a[i]) { fa[i]=a[i]; add(a[i],i); }
88     }
89     For(i,1,n) read(w[i]);
90     if(tpsort()==-1) puts("-1");
91     else {
92         For(i,1,n) {
93             sum[i]=w[i]; len[i]=1;
94             que.push(node(i,1,sum[i])); 
95         }
96         printf("%lld
",solve());
97     }
98     return 0;
99 }
View Code

d2t3[HNOI/AHOI2018]道路

一道水题,直接树形dp,记录上面的公路和铁路的条数.

一开始不知道为什么以为是满二叉树,空间炸了.

深度有40,不炸空间要开map存.

  1 //Achen
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<vector>
  7 #include<cstdio>
  8 #include<queue>
  9 #include<cmath>
 10 #include<set>
 11 #include<map>
 12 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 14 const int N=40007;
 15 typedef long long LL; 
 16 typedef double db;
 17 using namespace std;
 18 LL n,a[N],b[N],c[N],gls[N],tls[N];
 19 map<int,LL>dp[N];
 20 
 21 template<typename T> void read(T &x) {
 22     char ch=getchar(); x=0; T f=1;
 23     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
 24     if(ch=='-') f=-1,ch=getchar();
 25     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
 26 }
 27 
 28 void add(int u,int v,int o) {
 29     if(!o) gls[u]=v;
 30     else tls[u]=v;
 31 }
 32 
 33 void dfs(int x,int l1,int l2) { //i gonglu
 34     if(!gls[x]) {
 35         For(i,0,l1) For(j,0,l2) dp[x][i*100+j]=c[x]*(a[x]+i)*(b[x]+j);
 36         return ;
 37     }
 38     int gl=gls[x],tl=tls[x];
 39     dfs(gl,l1+1,l2); dfs(tl,l1,l2+1);
 40     For(i,0,l1) For(j,0,l2) 
 41         dp[x][i*100+j]=min(dp[gl][i*100+j]+dp[tl][i*100+j+1],dp[gl][(i+1)*100+j]+dp[tl][i*100+j]);
 42 }
 43 
 44 //#define DEBUG
 45 int main() {
 46 #ifdef DEBUG
 47     freopen("road.in","r",stdin);
 48     freopen("road.out","w",stdout);
 49 #endif
 50     read(n);
 51     For(i,1,n-1) {
 52         int si,ti;
 53         read(si); read(ti);
 54         if(si>0) add(i+n,n+si,0);
 55         else add(i+n,-si,0);
 56         if(ti>0) add(i+n,n+ti,1);
 57         else add(i+n,-ti,1);
 58     }
 59     For(i,1,n) { read(a[i]); read(b[i]); read(c[i]); }
 60     dfs(1+n,0,0);
 61     printf("%lld
",dp[n+1][0]);
 62     return 0;
 63 }
 64 /*
 65 6
 66 2 3
 67 4 5
 68 -1 -2
 69 -3 -4
 70 -5 -6
 71 1 2 3
 72 1 3 2
 73 2 1 3
 74 2 3 1
 75 3 1 2
 76 3 2 1
 77 
 78 9
 79 2 -2
 80 3 -3
 81 4 -4
 82 5 -5
 83 6 -6
 84 7 -7
 85 8 -8
 86 -1 -9
 87 1 60 1
 88 1 60 1
 89 1 60 1
 90 1 60 1
 91 1 60 1
 92 1 60 1
 93 1 60 1
 94 1 60 1
 95 1 60 1
 96 
 97 12
 98 2 4
 99 5 3
100 -7 10
101 11 9
102 -1 6
103 8 7
104 -6 -10
105 -9 -4
106 -12 -5
107 -2 -3
108 -8 -11
109 53 26 491
110 24 58 190
111 17 37 356
112 15 51 997
113 30 19 398
114 3 45 27
115 52 55 838
116 16 18 931
117 58 24 212
118 43 25 198
119 54 15 172
120 34 5 524
121 */
View Code

Orz cai大佬day2AK进队

Orz sxyday2AK吊打我这种辣鸡滚粗选手

你们都太强啦%%%

原文地址:https://www.cnblogs.com/Achenchen/p/8921650.html