首页 > 其他分享 >The 2021 ICPC Asia Shenyang Regional Contest

The 2021 ICPC Asia Shenyang Regional Contest

时间:2022-10-31 20:46:48浏览次数:93  
标签:Regional const Contest int Shenyang -- Complex return 2n

The 2021 ICPC Asia Shenyang Regional Contest

我们按难易程度来,E,F<B,J<H,I,L,M

E. Edward Gaming, the Champion

直接输出edgnb子字符串数量。

F. Encoded Strings I

分析

对每一个前缀进行一次判断:

从后往前更新,用一个set来维护已经出现的字符。如果这个字符是第一次出现,那么就更新它的映射 \(mp[c] = char('a' + st.size())\),并把它插入set。

AC_code

#include <bits/stdc++.h>
using namespace std;
string fuc(string s){
    int n = s.size();
    set<char> st;
    map<char, char> mp;
    for(int i = n - 1; i >= 0; i --){
        if(!st.count(s[i])){
            mp[s[i]] = char('a' + st.size());
            st.insert(s[i]);
        }
    }
    for(char& c : s){
        c = mp[c];
    }
    return s;
}
void solve(){
    int n; string s;
    cin >> n >> s;
    vector<string> st;
    for(int i = 1; i <= n; i ++){       
        st.push_back(fuc(s.substr(0, i)));
    }
    sort(st.begin(), st.end());
    cout << st[n - 1];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    return 0;
}

B. Bitwise Exclusive-OR Sequence

题目大意

有一个数组a,长度为n,给出m个限制,每个限制为\(a_i \oplus a_j = w\),求满足条件的最小的数组的所有的数的和。

分析

由于涉及位运算,我们考虑对每一位单独操作。我们假设当前考虑的是bit位。

我们来思考一下限制有什么作用呢?我们分两种情况。

  • \((a_i \oplus a_j)>>bit\ \&\ 1=1\),则代表\(a_i\)与\(a_j\)在bit位一定不同。
  • \((a_i \oplus a_j)>>bit\ \&\ 1=0\),则代表\(a_i\)与\(a_j\)在bit位一定相同。

这让我们想到了什么,不同的划分到一个集合去,相同的划分到一个集合去。利用扩展域并查集就可以实现该操作了。

AC_code

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using ll = long long;
using namespace std;
const int N = 2e5 + 10,M = N*2;
struct Node
{
    int u,v,w;
}edges[N];

int p[N],sz[N];
bool vis[N];

int find(int x)
{
    if(p[x]!=x) p[x] = find(p[x]);
    return p[x];
}

void solve() {
    int n,m;cin>>n>>m;
    for(int i=0;i<m;i++) 
    {
        int u,v,w;cin>>u>>v>>w;
        edges[i] = {u,v,w};
    }
    ll ans = 0;
    for(int i=0;i<30;i++)
    {
        for(int j=1;j<=2*n;j++) p[j] = j,vis[j] = 0;
        for(int j=1;j<=n;j++) sz[j] = 1;
        for(int j=n+1;j<=2*n;j++) sz[j] = 0;
        for(int j=0;j<m;j++)
        {
            auto [u,v,w] = edges[j];
            int pa = find(u),paa = find(u+n);
            int pb = find(v),pbb = find(v+n);
            if(w>>i&1)
            {
                if(pa==pb||paa==pbb) 
                {
                    cout<<"-1\n";
                    return ;
                }
                if(pa==pbb||paa==pb) continue;
                p[pa] = pbb;sz[pbb] += sz[pa];
                p[paa] = pb;sz[pb] += sz[paa];
            }
            else 
            {
                if(pa==pbb||pb==paa)   
                {
                    cout<<"-1\n";
                    return ;
                }
                if(pa==pb||paa==pbb) continue;
                p[pa] = pb;sz[pb] += sz[pa];
                p[paa] = pbb;sz[pbb] += sz[paa];
            }
        }
        for(int j=1;j<=n;j++)
        {
            int pa = find(j),pb = find(j+n);
            if(vis[pa]&&vis[pb]) continue;
            vis[pb] = vis[pa] = 1;
            ans += (1ll<<i)*min(sz[pa],sz[pb]);
        }
    }
    cout<<ans<<'\n';
}
 
int main() 
{
    ios;
    int T=1;
    // cin>>T;
 
    while(T -- ) {
        solve();
    }
 
    return 0;
}

J. Luggage Lock

题目大意

给两个字符串sted,都有四位。其中都为数字,从sted最少需要多少步。每一步,可以同时旋转相邻的几位,向上旋转或向下旋转。这里的向上旋转指的是同时+1,向下旋转同时-1。范围要限制在[0,9]中。

分析

直接说做法吧。

我们直接暴力求出从0000到所有的情况最短路。

然后T组样例时,我们做一个映射。

st映射到0000每一位需要调整的,同步调整到ed中。

AC_code

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using ll = long long;
using namespace std;
const int N = 15,M = N*2;

int dis[10010];

int get(int s,int x,int len,int ty)
{
    int a[4] = {s/1000%10,s/100%10,s/10%10,s%10};
    for(int i=x;i<x+len;i++)
        a[i] = (a[i] + ty + 10)%10;
    s = 0;
    for(int i=0;i<4;i++) s = a[i] + s*10;
    return s;
}

int find(string st,string ed)
{
    int res = 0;
    for(int i=0;i<4;i++) res = res*10 + (ed[i] - st[i] + 10)%10;
    return res;
}

void solve() {
    string st,ed;
    cin>>st>>ed;
    cout<<dis[find(st,ed)]-1<<'\n';
}
 
int main() 
{
    ios;
    int T=1;
    queue<int> q;
    q.push(0);
    dis[0] = 1;
    while(q.size())
    {
        auto t = q.front();q.pop();
        for(int len=1;len<=4;len++)
            for(int i=0;i<4-len+1;i++)
            {
                int res = get(t,i,len,1);
                if(!dis[res]) 
                {
                    dis[res] = dis[t] + 1;
                    q.push(res);
                }
                res = get(t,i,len,-1);
                if(!dis[res]) 
                {
                    dis[res] = dis[t] + 1;
                    q.push(res);
                }
            }     
    }
    cin>>T;
    while(T -- ) {
        solve();
    }
 
    return 0;
}

H. Line Graph Matching

题目大意

给出一个图,对一个点的两条边匹配,匹配得到的价值为两条边的权值和,这样能得到的最大的价值。

分析

我们分析后可以发现,如果图是偶数条边,那么一定可以全取到。

如果是奇数边,我们考虑将最小的一条边删除。

但是这里有个问题,如果最小的一条边是桥的话。我们删除后,会出现两个新的连通块。

其中包含两种情况。

  • 奇数-桥-奇数,那我们肯定是考虑,删除除桥外的最小的一条边,这样结果就是偶数-桥-奇数,剩下的我们都可以匹配成功。
  • 偶数-桥-偶数,那我们正常删桥就好了。

总结来说。

偶数的话,就直接输出所有边的权值和就好。

奇数的话,如果最小值不是桥,那么我们直接删最小值,如果是桥,只有这个桥两端的连通块是偶数的时候我们才删该桥。

我们用tarjan求桥

AC_code

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
using ll = long long;
const int N = 1e5 + 10,M = 4e5 + 10,inf = 0x3f3f3f3f;
int n,m,mi = inf,totedg;
int h[N],e[M],ne[M],w[M],idx;
int dfn[N],low[N],timestamp;
int sz[N],edge[N];

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx] = c,h[a]=idx++;
}

void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++timestamp;
    sz[u] = edge[u];
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(!dfn[j])
        {
            tarjan(j,u);
            sz[u] += sz[j];
            low[u]=min(low[u],low[j]);
            if(dfn[u]<low[j]) 
            {
                if((sz[j]-1)/2%2==0) 
                    mi = min(w[i],mi);
            }
            else mi = min(w[i],mi);

        }
        else if(j!=fa) low[u]=min(low[u],dfn[j]),mi = min(w[i],mi);//同时,没有标记数组后,我们每次都需要对low[u]进行更新。
        if(dfn[u]<dfn[j]) totedg++;
    }
}

int main()
{
    ios;cin>>n>>m;
    memset(h,-1,sizeof h);
    ll ans = 0;
    for(int i=0;i<m;i++)
    {
        int u,v,w;cin>>u>>v>>w;
        add(u,v,w),add(v,u,w);
        edge[u]++;edge[v]++;
        ans += w;
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
        {
            mi = inf;totedg = 0;
            tarjan(i,-1);
            if(totedg&1) ans -= mi;
        }
    cout<<ans<<'\n';
    return 0;
}

I. Linear Fractional Transformation

题目大意

定义\(f(z)=\frac{az+b}{cz+d},(a,b,c,d\in C),C为复数\)。

T组样例

每组样例给你\(z_1,f(z_1),z_2,f(z_2),z_3,f(z_3),z_4\),让你去计算\(f(z_4)\)的答案,保证\(f(z_4)\)的答案,保证\(f(z_4)\)有唯一解。

分析

由于有四个未知数,但是我们只有三个等式。但是本题保证一定有唯一解。因此,我们考虑将c当做已知。

分类讨论c

  • c{0,0},带入看是否能使\(z_1,z_2,z_3\)同时成立。

    由于d对判断成立并不影响,因此我们直接设d={1,0},带入\(z_1,z_2\),我们可以得到。

    \[az_1+b = f(z_1)\\ az_2+b = f(z_12) \]

    解出来可以得到

    \[a=\frac{w_1-w_2}{z_1-z_2}\\ b=w_1-az_1 \]

    接下来,我们用\(f(z_3)\)去验证a,b是否正确,正确的话,则\(f(z_4)\)也可以求出来。

  • c{1,0}

    我们当前有三个方程,有三个未知数a,b,d

    \[az_1+b-f(z_1)*d=f(z_1)*z_1\\ az_2+b-f(z_2)*d=f(z_2)*z_2\\ az_3+b-f(z_3)*d=f(z_3)*z_3 \]

    直接高斯消元解出来。

    将\(z_4\)带入得到答案。

AC_code

#include<bits/stdc++.h>
using namespace std;

const double eps = 1e-8;

struct Complex{
	double x, y;
	Complex operator+(const Complex &b) const {
		return Complex({x+b.x, y+b.y});
	}
	Complex operator-(const Complex &b) const {
		return Complex({x-b.x, y-b.y});
	}
	Complex operator*(const Complex &b) const {
		return Complex({x*b.x - y*b.y, x*b.y + y*b.x});
	}
	Complex operator/(const Complex &b) const {
		return Complex({(x*b.x + y*b.y)/(b.x*b.x + b.y*b.y), (y*b.x - x*b.y)/(b.x*b.x + b.y*b.y)});
	}
}A[5][5],  w[5], z[5];

double mo(Complex x){
    return x.x*x.x + x.y*x.y;
}

void Gauss() {
    //化成上三角矩阵
    int n = 3;
    for (int r = 1, c = 1; r <= n; ++ r, ++ c) {
        //找到主元
        int t = r;
        for (int i = r + 1; i <= n; ++ i)
            if (mo(A[i][c]) > mo(A[t][c]))
                t = i;
        //交换第r行和第t行的元素
        for (int i = c; i <= n + 1; ++ i) swap(A[r][i], A[t][i]);
        //主元归一(第r行除以主元系数)
        for (int i = n + 1; i >= c; -- i) A[r][i] = A[r][i] / A[r][c];
        //消元(用该行把下面所有行的第c列消为0)
        for (int i = r + 1; i <= n; ++ i) {
            for (int j = n + 1; j >= c; -- j) {
                A[i][j] = A[i][j] - A[r][j] * A[i][c];
            }
        }
    }
    //化成行最简阶梯型矩阵(本题唯一解,故同样也是对角矩阵)
    for (int i = n; i > 1; -- i) {
        for (int j = i - 1; j >= 1; -- j) {
            A[j][n + 1] = A[j][n+1] - A[i][n + 1] * A[j][i];
            A[j][i] = {0, 0};
        }
    }
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        for(int i=1;i<=3;i++)
        {
            double x,y;
            scanf("%lf%lf",&x,&y);z[i] = {x,y};
            scanf("%lf%lf",&x,&y);w[i] = {x,y};
        }
        Complex z4;double x,y;
        scanf("%lf%lf",&x,&y);
        z4 = {x, y};
		Complex a = (w[1] - w[2]) / (z[1] - z[2]); 
		Complex b = w[1] - a*z[1];
		Complex res = {-5, -5};
        if(mo(a*z[3] + b - w[3])<eps)
        {
            res = a*z4 + b;
        }
        else 
        {
            for (int i = 1; i <= 3; i ++ ) {
				A[i][1] = z[i];
				A[i][2] = {1, 0};
				A[i][3] = {-w[i].x, -w[i].y};
				A[i][4] = w[i]*z[i];
			}
			Gauss();
			res = (A[1][4]*z4 + A[2][4]) / (z4 + A[3][4]);
        }
        printf("%.8lf %.8lf\n",res.x,res.y);
    }
    return 0;
}


L. Perfect Matchings

题目大意

给一个2n大小的完全图,删除其中2n-1条边,其中2n-1条边形成一棵树。问完美匹配数量。

完美匹配,一个边集,这个边集中,任意两条边的端点不重合。

分析

我们没什么下手的地方,先想想如果不删我们怎么算呢?

这就是一个比较简单的组合问题了,我们可以将任意两个端点分成一组,然后就有n组,这n组的组成方案数就是完美匹配的方案数了。

我想的是,我们直接将2n个端点进行全排列\(A_{2n}^{2n}\),每相邻两个为一组,则有重复,一个重复是组内前后没区别,则除以\(2^n\),接下来n组的相对关系也是没区别,再除个\(A_{n}^{n}\)。则最后式子就是,\(\frac{A_{2n}^{2n}}{2^nA_{n}^{n}}\)。

我们的思路逐渐清晰了,我们从总体减去利用2n-1条边的不同方案。

那这些方案怎么算呢?这里有一个一般思路,我们暴力枚举一般都是不太行的,我们考虑用DP计算。

因为减去的2n-1条边是一棵树。则我们考虑定义状态为,f[i][j][0/1]:以i为根节点的子树,用了j条边,0表示根节点所在的边未被选中,1相反。所有的完美匹配方案数。

我们考虑最后统计时,枚举0-nf[1][x][0]+f[1][x][1]则表示,选中其中至少x条树边,其余的树边我们无法确定是否选择。因此这里使用了容斥原理。

这表示了已经匹配了2i个点,其余的2n-2i个点未匹配。剩余2n-2i的所有方案,我们已经知道了,即为\(y=\frac{A_{2n-2i}^{2n-2i}}{2^{n-i}A_{n-i}^{n-i}}\),则这种情况最终方案即为x*y

容斥原理,用了x条边的系数即为\((-1)^x\)。

这里为什么想到DP呢?

因为如果我们直接使用暴力枚举的话,则\(2^n\)种情况,但是其实很多情况是可以合并的。比如虽然选中的是不同的边,但是最后乘的y是相同的,因此可以直接合并,则时间复杂度直接就被降到\(O(n)\)。这里其实利用的就是加法原理。所以说虽然组合数学的加减乘除四个原理很基础,但是是我们解决后面很多问题的基石。

AC_code

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
using ll = long long;
const int N = 4010,mod = 998244353;

int h[N],ne[N<<1],e[N<<1],idx;
int f[N][N>>1][2],g[N>>1][2],sz[N];
int fact[N],infact[N],qpow[N];
int n;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int ksm(int a,int b)
{
    int res = 1;
    while(b)
    {
        if(b&1) res = 1ll*res*a%mod;
        a = 1ll*a*a%mod;
        b >>= 1;
    }
    return res;
}

void init(int x)
{
    qpow[0] = fact[0] = infact[0] = 1;ll inv = ksm(2,mod-2);
    for(int i=1;i<=x;i++) fact[i] = 1ll*fact[i-1]*i%mod,qpow[i] = inv*qpow[i-1]%mod;
    infact[x] = ksm(fact[x],mod-2);
    for(int i=x-1;i;i--) infact[i] = 1ll*infact[i+1]*(i+1)%mod;
}

int C(int a,int b)
{
    if(b>a) return 0;
    return 1ll*fact[a]*infact[b]%mod*infact[a-b]%mod;
}

void dfs(int u,int fa)
{
    sz[u] = f[u][0][0] = 1;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==fa) continue;
        dfs(j,u);
        memset(g,0,sizeof g);
        for(int i=0;i<=sz[u]/2;i++)
            for(int k=0;k<=sz[j]/2;k++)
            {
                g[i+k][0] = (g[i+k][0]+1ll*f[u][i][0]*(f[j][k][0]+f[j][k][1])%mod)%mod;
                g[i+k][1] = (g[i+k][1]+1ll*f[u][i][1]*(f[j][k][0]+f[j][k][1])%mod)%mod;
                g[i+k+1][1] = (g[i+k+1][1]+1ll*f[u][i][0]*f[j][k][0]%mod)%mod;
            }
        for(int i=0;i<=sz[u]/2+sz[j]/2+1;i++) f[u][i][0] = g[i][0],f[u][i][1] = g[i][1];
        sz[u] += sz[j];
    }
}

int main()
{
    ios;
    int n;cin>>n;
    memset(h,-1,sizeof h);
    init(2*n);
    for(int i=0;i<2*n-1;i++)
    {
        int u,v;cin>>u>>v;
        add(u,v),add(v,u);
    }
    dfs(1,-1);
    ll ans = 0;
    for(int i=0;i<=n;i++)
    {
        ll x = (f[1][i][0]+f[1][i][1])%mod;
        int t = n - i;
        ll y = 1ll*fact[2*t]*infact[t]%mod*qpow[t]%mod;
        if(i&1) ans = (ans-x*y%mod+mod)%mod;
        else ans = (ans + x*y%mod)%mod;
    }
    cout<<ans<<'\n';
    return 0;
}

M. String Problem

分析

队友写的,听说不难。

后缀数组&&LCP

一个字符串的字典序最大的子串是这个字符串字典序最大的后缀。

从后往前更新,用 \(now\) 来记录已经更新过的答案

对于排名第 \(i\) 位的后缀,往前找到第一个 \(j < i,sa[j] < sa[i]\) 的排名为 \(j\) 后缀 , 他对答案的贡献是 \([sa[i] + lcp(i, j), now]\)

AC_code

#include <bits/stdc++.h>
using namespace std;

const int N = 1000010;
int n, sa[N], rk[N], oldrk[N << 1];
int id[N], px[N], cnt[N], height[N];
int ans[N];
bool cmp(int x, int y, int w) {
    return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}
void solve() {
    int i, m = 300, p, w;
    string s; cin >> s; n = s.size();
    s = " " + s;
    
    for(int i = 0; i <= m; i ++) cnt[i] = 0;
    
    for (i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]];
    for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
    for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;
    for (w = 1;; w <<= 1, m = p) {
        for (p = 0, i = n; i > n - w; --i) id[++p] = i;
        for (i = 1; i <= n; ++i)
            if (sa[i] > w) id[++p] = sa[i] - w;
        memset(cnt, 0, (m + 3) * sizeof(int));
        for (i = 1; i <= n; ++i) ++cnt[px[i] = rk[id[i]]];
        for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1];
        for (i = n; i >= 1; --i) sa[cnt[px[i]]--] = id[i];
        memcpy(oldrk, rk, (n + 3) * sizeof(int));
        for (p = 0, i = 1; i <= n; ++i)
            rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
        if (p == n) {
            for (int i = 1; i <= n; ++i) sa[rk[i]] = i;
            break;
        }
    }
    for (int i = 1, k = 0; i <= n; ++i) {
        if (k) --k;
        while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
        height[rk[i]] = k;
    }

    for(int i = 1; i <= n; i ++){
        cout << sa[i] << ' ';
    }
    cout << "\n";

    int now = n;
    for(int i = n; i; i --){
        int j = i - 1;
        int h = height[i];
        while(j && sa[i] < sa[j]){
            h = min(h, height[j]);
            j --;
        }
        if(j <= 0){
            for(int k = now; k; k --) ans[k] = sa[i];
            break;
        }
        for(int j = now; j >= sa[i] + h; j --) ans[j] = sa[i];
        now = sa[i] + h - 1;
        if(now <= 0) break;
        i = j + 1;
    }
    for(int i = 1; i <= n; i ++){
        cout << ans[i] << ' ' << i << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    int T = 1; //cin >> T; 
    while (T --) {
        solve();
    }
    return 0;
}

标签:Regional,const,Contest,int,Shenyang,--,Complex,return,2n
From: https://www.cnblogs.com/aitejiu/p/16845695.html

相关文章

  • Team Extra Contest 2022-10-21补题
    D.38parrots线段树#include<bits/stdc++.h>usingnamespacestd;#defineIOSios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)#definerep(a,b......
  • AtCoder Beginner Contest 275 D~F
    D-YetAnotherRecursiveFunction思路:直觉需要用到的数字大多数是重复的,所以记忆化了一下,测了一下1e18的数据,跑的飞快,直接交了,6ms。#include<bits/stdc++.h>#def......
  • AtCoder Beginner Contest 275 E F
    E-Sugoroku4题意:从0走到n,有k次操作,每次会丢出一个骰子,骰子上的数字为\([1,m]\),等概率出现问到达n的概率思路:\(dp[i][k]\)表示用了k次操作到达位置i的概......
  • Atcoder Beginner Contest 275(A~F)
    我好菜啊……又没切掉F,40+min切掉A~E成功滚粗。希望能越打越好吧……赛时A求序列最大值,B简单计算,C数正方形,跳过。D递推不太行,N的范围有点大。但是除法的转移......
  • AtCoder Beginner Contest 275
    咕咕咕咕咕咕。G-InfiniteKnapsack做法1-二分假设第\(i\)个物品选了\(x_i\)个,\(x_i\)为非负整数,有\[\lim_{x\to+\infin}\frac{f(x)}{x}=\frac{\sum_ic_......
  • AtCoder Regular Contest 060
    F题有循环节,一看就有KMP,比较难,太晚了,早上起来再补。C-TakandCards\(n\)个整数\(a_1\sima_n\),问有多少种选数方案,使得选出来的数平均值为\(A\)。\(1\len,a_i......
  • Weekly Contest 315
    WeeklyContest315ProblemALargestPositiveIntegerThatExistsWithItsNegative思路按照题目要求暴力求一下代码classSolution:deffindMaxK(self,num......
  • AtCoder Regular Contest 059
    EducationalDPRound(确信C-BeTogether给定\(n\)个数\(a_{1}\sima_n\),你至多可以对每个\(a_i\)操作一次,以\((a_i-y)^2\)的代价令\(a_i\getsy\),求\(a\)全......
  • Atcoder Grand Contest 003(A~F)
    赛时打了80分钟,后来因为要处理一些私事就没再打,过掉了ABC,推了DE没推出来,不能算很差,但也不算很好。总结一下吧。赛时A一眼题,统计四个方向是否出现过,如果相对的两......
  • [线段树套单调栈] 2019-2020 ICPC Asia Hong Kong Regional Contest H.[Hold the Line
    线段树套单调栈2019-2020ICPCAsiaHongKongRegionalContestH.​​HoldtheLine​​题目大意你已经建造了一条由编号从到的战壕组成的防线,每条战壕最初都是空的。士......