CodeForces Educational Codeforces Round 51 (Rated for Div. 2)

A:Vasya And Password

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;
char s[N];
int main(){
    int T;
    int low, upp, dig;
    scanf("%d", &T);
    while(T--){
        scanf("%s", s);
        int len = strlen(s);
        low = upp = dig = 0;
        for(int i = 0; i < len; ++i){
            if(islower(s[i])) low++;
            else if(isupper(s[i])) upp++;
            else dig++;
        }
        if(low == 0 && upp == 0){
            s[0] = 'A';
            s[1] = 'a';
        }
        else if(low == 0 && dig == 0) s[0] = 'a', s[1] = '1';
        else if(dig == 0 && upp == 0) s[0] = '1', s[1] = 'A';
        else if(low == 0){
            if(upp > 1) {for(int i = 0; i < len; ++i) if(isupper(s[i])) {s[i] = 'a'; break;};}
            else {for(int i = 0; i < len; ++i) if(isdigit(s[i])) {s[i] = 'a'; break;};}
        }
        else if(dig == 0){
            if(upp > 1) {for(int i = 0; i < len; ++i) if(isupper(s[i])) {s[i] = '1'; break;};}
            else {for(int i = 0; i < len; ++i) if(islower(s[i])) {s[i] = '1'; break;};}
        }
        else if(upp == 0){
            if(low > 1) {for(int i = 0; i < len; ++i) if(islower(s[i])) {s[i] = 'A'; break;};}
            else {for(int i = 0; i < len; ++i) if(isdigit(s[i])) {s[i] = 'A'; break;};}
        }
        printf("%s
", s);
    }
    return 0;
}
View Code

B:Relatively Prime Pairs

相邻2位gcd一定为1。

代码:

Copy
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;

int main(){
    LL l, r;
    scanf("%lld%lld", &l , &r);
    if((r-l+1)&1) puts("NO");
    else {
        puts("YES");
        for(LL i = l; i <= r; i += 2){
            printf("%lld %lld
", i, i+1);
        }
    }
    return 0;
}
View Code

C:Vasya and Multisets

题意:将所有数分组,要求2个组的完美数的数量相等。

题解:

只有数量为1的数和数量大于2的数才会影响平衡。

数量为2的数,如果选1个放在左边,则另一个就会放在右边。

数量>2的数,就可以把他变成1个完美数+1个不完美数,或者是1个不完美数。

数量为一的数,一定是完美数。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100;
int vis[N];
int a[N];
int ok[N];
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &a[i]);
        ++vis[a[i]];
    }
    int n1 = 0, n2 = 0;
    for(int i = 1; i <= 100; ++i){
        if(vis[i] == 1) ++n1;
        if(vis[i] > 2) ++n2;
    }
    if(n1 & 1){
        if(n2){
            puts("YES");
            n2 = 1;
            n1 /= 2;
            for(int i = 1; i <= n; ++i){
                if(vis[a[i]] >= 3 && n2){
                    printf("A");
                    n2--;
                }
                else if(vis[a[i]] == 1 && n1){
                    printf("A");
                    n1--;
                }
                else printf("B");
            }
        }
        else {
            puts("NO");
        }
    }
    else {
        n1 /= 2;
        puts("YES");
        for(int i = 1; i <= n; ++i){
            if(vis[a[i]] == 1 && n1){
                printf("A");
                n1--;
            }
            else printf("B");
        }
    }
    return 0;
}
View Code

D:Bicolorings

题意:2×m的格子,求联通块为k的方案数。

题解:DP.

dp[i][k][z1][z2]代表的是处理到第i个位置,有k个联通块,上面颜色为z1,下面颜色为z2的方案数。

然后我们就可以枚举 dp[i-1]的方案,把值加到dp[i][k][z1][z2]上来。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  998244353;
const int N = 1e3+10;
LL dp[N][N<<1][2][2];
int main(){
    dp[1][1][0][0] = dp[1][1][1][1] = 1;
    dp[1][2][0][1] = dp[1][2][1][0] = 1;
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 2; i <= n; ++i){
        for(int k = 1; k <= m; ++k){
            dp[i][k][0][0] = (dp[i-1][k][0][0] + dp[i-1][k][0][1] + dp[i-1][k][1][0] + dp[i-1][k-1][1][1]) % mod;
            dp[i][k][1][1] = (dp[i-1][k][1][1] + dp[i-1][k][0][1] + dp[i-1][k][1][0] + dp[i-1][k-1][0][0]) % mod;
            dp[i][k][0][1] = (dp[i-1][k-1][0][0] + dp[i-1][k-1][1][1] + dp[i-1][k][0][1]);
            dp[i][k][1][0] = (dp[i-1][k-1][0][0] + dp[i-1][k-1][1][1] + dp[i-1][k][1][0]);
            if(k > 1){
                dp[i][k][0][1] += dp[i-1][k-2][1][0];
                dp[i][k][1][0] += dp[i-1][k-2][0][1];
            }
            dp[i][k][0][1] %= mod;
            dp[i][k][1][0] %= mod;
        }
    }
//    cout << dp[2][2][0][1] << " " << dp[2][2][1][0] << " " << dp[2][4][0][1] << " " << dp[2][4][1][0] << endl;
    LL ans = 0;
    ans = dp[n][m][0][0] + dp[n][m][1][1] + dp[n][m][1][0] + dp[n][m][0][1];
    ans %= mod;
    cout << ans << endl;
    return 0;
}
View Code

E:Vasya and Big Integers

题意:问将一个字符串,分成若干段,要求每一段都的值都 <= l && <= r,求可行的方案数。

题解:字符串hash * 二分 + DP 或者 Z-function + DP。

方案数通过DP转移。那么我们就需要求出哪一段是可以转移到当前的。

如果需要大于L,那么就是往前走L-len步, 然后再判断这个位置开始的字符串可以不可以作为起点,不可以就往前走一步。

如果需要小于R,那么就是往前走R-len步,然后再判断这个位置开始的字符串是不是可以作为终点,不可以就往后走一步。

现在的问题就是怎么判断。

方法1,就是hash字符串之后,通过二分找到第一个hash值不相等的地方,然后再判断接来下字母的大小。

方法2,就是通过Z-function,找到每个位置能匹配的最大长度,如果不能完全匹配,那么就判断不匹配位置的字符大小。

接下来的问题就是前导0的问题。

定义sum[i]为到i为止方案数的前缀和,并且不包括有0可能作为前导出现的情况,也就是说当处理到a[i]的时候,只有当a[i+1]!=0的时候我们才会把东西放进去。

定义val[i]为i的方案数。

那么我们就可以避免前导0的情况了。

现在还需要考虑单独为0的情况,如果当前为‘0’,并且L = ‘0’,那么就可以 val[i] += val[i-1]。

代码1:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod = 998244353;
const int N = 1e6 + 100;
char l[N], r[N], s[N];
LL sum[N];
LL v[N];
LL base = 397;
int Mod = 1e9+7;
ULL Hash[N], s_val[N], l_val[N], r_val[N];
int len1, len2, len3;
void init(){
    Hash[0] = 1;
    for(int i = 1; i < N; ++i) Hash[i] = (Hash[i-1] * base) % Mod;
    for(int i = 1; i <= len1; ++i) s_val[i] = (s_val[i-1] * base + s[i] - '0' + 1)%Mod;
    for(int i = 1; i <= len2; ++i) l_val[i] = (l_val[i-1] * base + l[i] - '0' + 1)%Mod;
    for(int i = 1; i <= len3; ++i) r_val[i] = (r_val[i-1] * base + r[i] - '0' + 1)%Mod;
}
ULL G1(int ll, int rr){
    return (s_val[rr] - s_val[ll-1] * Hash[rr-ll+1]%Mod+Mod)%Mod;
}
ULL G2(int ll, int rr){
    return l_val[rr];
}
ULL G3(int ll, int rr){
    return r_val[rr];
}
bool check1(int lp){
    if(lp < 1) return false;
    if(G1(lp, lp+len2-1) == G2(1,len2)) return true;
    int ll = 1, rr = len2;
    while(ll <= rr){
        int mid = ll+rr >> 1;
        if(G1(lp, lp+mid-1) == G2(1,mid)) ll = mid+1;
        else rr = mid - 1;
    }
    return s[lp+ll-1] > l[ll];
}
bool check2(int rp){
    if(rp < 1) return true;
    if(G1(rp,rp+len3-1) == G3(1,len3)) return true;
    int ll = 1, rr = len3;
    while(ll <= rr){
        int mid = ll+rr >> 1;
        if(G1(rp,rp+mid-1) == G3(1,mid)) ll = mid+1;
        else rr = mid-1;
    }
    return s[rp+ll-1] < r[ll];
}
int lpos[N];
int rpos[N];
LL val[N];
int main(){
    scanf("%s", s+1); scanf("%s", l+1);
    scanf("%s", r+1); len1 = strlen(s+1);
    len2 = strlen(l+1); len3 = strlen(r+1);
    init();
    int ok = 0;
    if(len2 == 1 && l[1] == '0') ok = 1;
    sum[0] = 1;
    for(int i = 1; i <= len1; ++i){
        sum[i] += sum[i-1];
        if(ok && s[i] == '0') val[i] += val[i-1];
        int lp = i - (len2-1);
        if(!check1(lp)) lp--;
        if(lp < 1) continue;
        int rp = i - (len3-1);
        if(!check2(rp)) rp++;
        if(rp < 1) rp = 1;
        if(lp < rp) continue;
        val[i] += sum[lp-1];
        if(rp-2 >= 0) val[i] -= sum[rp-2];
        val[i] = ((val[i] % mod) + mod ) % mod;
        if(s[i+1] != '0') sum[i] = (sum[i]+val[i]) % mod;
    }
    printf("%lld
", val[len1]);
    return 0;
}
/*
156156748948919764684894891894874874891981
1
581684

*/
View Code

代码2:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod = 998244353;
const int N = 1e6 + 100;
char l[N], r[N], s[N];
LL sum[N];
LL v[N];
LL base = 397;
int Mod = 1e9+7;
ULL Hash[N], s_val[N], l_val[N], r_val[N];
int len1, len2, len3;
int posl[N];
int posr[N];
int z[N*2];
char ss[N*3];
void init(){
    strcpy(ss, l+1);
    ss[len2] = '#';
    strcpy(ss+len2+1, s+1);
    int n = len1 + 1 + len2, j = 1;
    z[0] = n;
    int k;
    for(int i=1;i<n;i=k){
        if(j < i) j = i;
        while (j < n && ss[j] == ss[j-i]) j++;
        z[i]=j-i;
        k=i+1;
        while (k+z[k-i]<j){
                z[k]=z[k-i];k++;
        }
    }
    for(int i = 1; i <= len1; ++i) posl[i] = z[len2+i];
    strcpy(ss, r+1);
    ss[len3] = '#';
    strcpy(ss+len3+1, s+1);
    n = len1 + 1 + len3;
    z[0] = n;
    j = 1;
    for(int i=1 ;i < n; i=k){
        if(j < i) j = i;
        while (j < n && ss[j] == ss[j-i]) j++;
        z[i]=j-i;
        k = i+1;
        while (k+z[k-i]<j){
                z[k]=z[k-i];k++;
        }
    }
    for(int i = 1; i <= len1; ++i) posr[i] = z[len3+i];
}
LL val[N];
bool check1(int p){
    if(p < 1) return false;
    if(posl[p] == len2) return true;
    return s[p+posl[p]] >= l[posl[p]+1];
}
bool check2(int p){
    if(p < 1) return true;
    if(posr[p] == len3) return true;
    return s[p+posr[p]] <= r[posr[p]+1];
}
int main(){
    scanf("%s", s+1); scanf("%s", l+1);
    scanf("%s", r+1); len1 = strlen(s+1);
    len2 = strlen(l+1); len3 = strlen(r+1);
    init();
    int ok = 0;
    if(len2 == 1 && l[1] == '0') ok = 1;
    sum[0] = 1;
    for(int i = 1; i <= len1; ++i){
        sum[i] += sum[i-1];
        if(ok && s[i] == '0') val[i] += val[i-1];
        int lp = i - (len2-1);
        if(!check1(lp)) lp--;
        if(lp < 1) continue;
        int rp = i - (len3-1);
        if(!check2(rp)) rp++;
        if(rp < 1) rp = 1;
        if(lp < rp) continue;
        val[i] += sum[lp-1];
        if(rp-2 >= 0) val[i] -= sum[rp-2];
        val[i] = ((val[i] % mod) + mod ) % mod;
        if(s[i+1] != '0') sum[i] = (sum[i]+val[i]) % mod;
    }
    printf("%lld
", val[len1]);
    return 0;
}
/*
156156748948919764684894891894874874891981
1
581684

*/
View Code

F:The Shortest Statement

题意:问2点之间最短的距离。

题解:套路题。枚举边+lca。

需要注意到 m-n <= 20。

那么我们就可以枚举边了,我们先把所有的边加入进来的时候,用并查集维护联通块的信息,如果发现不加某条边也是联通的情况,就把这条边的编号存下来。

然后我们把存下来的边枚举一遍更新所有的答案。

然后在把所有存下来的边都ban掉,然后跑lca在更新一遍答案。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<LL,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 1e5 + 100, M = 4e5+100;
int pre[N];
int head[N], to[M], nt[M], ct[M], tot, ok[M];
void add(int u, int v, int w){
    to[tot] = v;
    ct[tot] = w;
    nt[tot] = head[u];
    head[u] = tot++;
}
int Find(int x){
    if(x == pre[x]) return x;
    return pre[x] = Find(pre[x]);
}
pll p[N];
LL ans[N];
vector<int> vc;
LL d[N][2];

void Dij(int u, int op){
    priority_queue<pll, vector<pll>, greater<pll> > pq;
    d[u][op] = 0;
    pq.push(pll(0,u));
    while(!pq.empty()){
        int x = pq.top().se; LL dis = pq.top().fi;
        pq.pop();
        if(d[x][op] > dis) continue;
        for(int i = head[x], v; ~i; i = nt[i]){
            v = to[i];
            if(ok[i]) continue;
            if(d[v][op] > d[x][op] + ct[i]){
                d[v][op] = d[x][op] + ct[i];
                pq.push(pll(d[v][op],v));
            }
        }
    }
}
int anc[N][20];
LL sum[N];
int deep[N];
int Log = 20;
void dfs(int o, int u){

    deep[u] = deep[o] + 1;
    anc[u][0] = o;
    for(int i = 1; i < Log; ++i) anc[u][i] = anc[anc[u][i-1]][i-1];
    for(int i = head[u],v; ~i; i = nt[i]){
        v = to[i];
        if(v == o || ok[i]) continue;
        sum[v] = sum[u] + ct[i];
        dfs(u,v);
    }
}
int lca(int u, int v){
    if(deep[u] > deep[v]) swap(u,v);
    int k = deep[v] - deep[u];
    for(int i = Log-1; i >= 0; --i)
        if((k>>i)&1) v = anc[v][i];
    if(u == v) return u;
    for(int i = Log-1; i >= 0; --i)
        if(anc[u][i] != anc[v][i])
            u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
LL dis(int u, int v){
    return sum[u]+sum[v] - 2*sum[lca(u,v)];
}
int main(){
    int n, m, q;
    scanf("%d%d", &n, &m);
    memset(head, -1, sizeof (head));
    memset(ans, INF, sizeof(ans));
    for(int i = 1; i <= n; ++i) pre[i] = i;
    int u,v,w;
    for(int i = 1; i <= m; ++i){
        scanf("%d%d%d", &u, &v, &w);
        add(u,v,w);
        add(v,u,w);
        u = Find(u), v = Find(v);
        if(u == v) vc.pb(tot-2);
        else pre[u] = v;
    }
    scanf("%d", &q);
    for(int i = 1; i <= q; ++i)
        scanf("%d%d", &p[i].fi, &p[i].se);
    for(int x : vc){
        ok[x] = 1; ok[x^1] = 1;
        memset(d, INF, sizeof(d));
        Dij(to[x], 1);
        Dij(to[x^1], 0);
        for(int i = 1; i <= q; ++i){
            ans[i] = min3(ans[i], d[p[i].fi][0]+d[p[i].se][1]+ct[x],d[p[i].fi][1]+d[p[i].se][0]+ct[x]);
        }
        ok[x] = 0; ok[x^1] = 0;
    }
    for(int x : vc) ok[x] = ok[x^1] = 1;
    dfs(0,1);
    for(int i = 1; i <= q; ++i)
        ans[i] = min(ans[i], dis(p[i].fi, p[i].se));
    for(int i = 1; i <= q; ++i)
        printf("%lld
", ans[i]);

    return 0;
}
View Code

G:Distinctification

题意:问最小花费。

题解:线段树合并。

我们每次插入一个点之前,先判断一下这个点是不是已经加过数了,如果加过数了我们就把这个数先往后移动,移动到没有加过数的地方。

然后现在一定是一个没有加过数的位置了,然后我们用动态线段树维护信息,注意我们插入的位置是b的。

然后在当前位置前面的有没有出现过数,有就和前面的合并。

对于后面的一样处理。

然后在合并的过程中,我们明白后面大的数一定是要到左边去的。

所以在合并的时候就更新答案。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 5e6;
int n;
struct Node{
    int ls, rs, num;
    LL sum;
    Node(){
        ls = rs = num = sum = 0;
    }
}tr[N];
int tot;
void Insert(int &p, int b, int l, int r){
    if(p == 0) p = ++tot;
    if(l == r) {
        ++tr[p].num;
        tr[p].sum = b;
        return ;
    }
    int m = l+r >> 1;
    if(b <= m) Insert(tr[p].ls, b, l, m);
    else Insert(tr[p].rs, b, m+1, r);
    tr[p].sum = tr[ tr[p].ls ].sum + tr[ tr[p].rs ].sum;
    tr[p].num = tr[ tr[p].ls ].num + tr[ tr[p].rs ].num;
}
LL ans = 0;
int Merge(int l, int r, int px, int py){
    if(!px) return py;
    if(!py) return px;
    tr[px].num += tr[py].num;
    tr[px].sum += tr[py].sum;
    if(l != r){
        int m = l+r >> 1;
        ans = ans - tr[tr[py].rs].sum * tr[tr[px].ls].num + tr[tr[px].ls].sum * tr[tr[py].rs].num;
        tr[px].ls = Merge(l, m, tr[px].ls, tr[py].ls);
        tr[px].rs = Merge(m+1, r, tr[px].rs, tr[py].rs);
    }
    return px;
}
int pre[N];
int r[N], rt[N];
int Find(int x){
    if(x == pre[x]) return x;
    return pre[x] = Find(pre[x]);
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i < N; ++i){
        pre[i] = i;
        r[i] = i;
    }
    int a, b;
    for(int i = 1; i <= n; ++i){
        scanf("%d%d", &a, &b);
        if(rt[a] != 0){
            int p = Find(a);
            int rr = r[p] + 1;
            ans += 1ll * b * (rr-a);
            a = rr;
        Insert(rt[a], b, 1, n);
        if(rt[a-1] != 0){
            int lx = Find(a-1);
            r[lx] = a;
            pre[a] = lx;
            rt[lx] = Merge(1,n,rt[lx],rt[a]);
        }
        if(rt[a+1] != 0){
            int rx = Find(a+1);
            int lx = Find(a);
            r[lx] = r[rx];
            pre[rx] = lx;
            rt[lx] = Merge(1,n,rt[lx],rt[rx]);
        }
        printf("%lld
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/MingSD/p/10130789.html