1. 程式人生 > >NOI2017 部分題解

NOI2017 部分題解

D1

T1
模擬一個很大的二進位制加減法
壓位線段樹,每個位置壓二進位制的30位,每次修改涉及1~2個位置,分別修改
對於一個位置i +/-,至多產生1個進/退位,相當於在i+1~inf +/- 1,找到>=i的位置中最小的非1/0位,中間的全部改0/1,這一位+/-1

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long using namespace std; inline void read(int &x) { char c; int
f=1; while(!((c=getchar())>='0'&&c<='9')) if(c=='-') f=-f; x=c-'0'; while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0'; x*=f; } const int maxn = 2100000; int n,m; int seg[maxn<<2]; void pushdown(const int x) { if(seg[x]!=-1) seg[x<<1]=seg[x<<1|1]=seg[x]; } void
pushup(const int x) { seg[x]=seg[x<<1]==seg[x<<1|1]?seg[x<<1]:-1; } int loc; int search(const int x,const int l,const int r) { if(l==r) return x; pushdown(x); int mid=l+r>>1; if(loc<=mid) search(x<<1,l,mid); else search(x<<1|1,mid+1,r); } int lx,rx,c; int find0(const int x,const int l,const int r) { if(r<lx||seg[x]==(1<<30)-1) return -1; if(l==r) { seg[x]++; rx=r-1; return 1; } pushdown(x); int mid=l+r>>1; int re=find0(x<<1,l,mid); if(re!=-1) { pushup(x); return re; } re=find0(x<<1|1,mid+1,r); pushup(x); return re; } int find1(const int x,const int l,const int r) { if(r<lx||seg[x]==0) return -1; if(l==r) { seg[x]--; rx=r-1; return 1; } pushdown(x); int mid=l+r>>1; int re=find1(x<<1,l,mid); if(re!=-1) { pushup(x); return re; } re=find1(x<<1|1,mid+1,r); pushup(x); return re; } void upd(const int x,const int l,const int r) { if(rx<l||r<lx) return; if(lx<=l&&r<=rx) { seg[x]=c; return; } pushdown(x); int mid=l+r>>1; upd(x<<1,l,mid); upd(x<<1|1,mid+1,r); pushup(x); } void add(const int k,const int v) { loc=k; int x=search(1,0,n); seg[x]+=v; int ci=seg[x]>=(1<<30)?1:0; seg[x]&=(1<<30)-1; while(x) x>>=1,pushup(x); if(ci) { lx=k+1; find0(1,0,n); c=0; if(lx<=rx) upd(1,0,n); } } void dec(const int k,const int v) { loc=k; int x=search(1,0,n); seg[x]-=v; int ci=seg[x]<0?1:0; if(seg[x]<0) seg[x]+=1<<30; while(x) x>>=1,pushup(x); if(ci) { lx=k+1; find1(1,0,n); c=(1<<30)-1; if(lx<=rx) upd(1,0,n); } } int query(const int k) { loc=k/30; int x=search(1,0,n); return seg[x]>>k-loc*30&1; } int main() { scanf("%d%*d%*d%*d",&m); n=m+2; while(m--) { int t,x,y; read(t); if(t==1) { read(x); read(y); int sig=1; if(x<0) sig=-1,x=-x; int d=y/30*30,u=d+30; int cc=0; for(int i=0;i<30&&y+i<u;i++) if(x>>i&1) cc|=1<<i+y-d; if(cc) { if(sig==1) add(d/30,cc); else dec(d/30,cc); } cc=0; for(int i=u-y;i<30;i++) if(x>>i&1) cc|=1<<i-(u-y); if(cc) { if(sig==1) add(u/30,cc); else dec(u/30,cc); } } else read(x),printf("%d\n",query(x)); } return 0; }

T2
我沒過這題…卡常卡了一個上午沒卡過去…深深的怨念
因為詢問的字串長度k<=50,實際上我們只關心長度<=k的串的出現次數,每次合併/分開兩個串,至多影響k^2個串的出現次數
所以離線,hash表維護詢問的所有子串的出現次數,雙hash

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int oo[10],on;
inline void output(int x)
{
    if(!x) { puts("0");return; }
    while(x)
    {
        int y=x/10; oo[++on]=x-y*10;
        x=y;
    }
    while(on) putchar('0'+oo[on--]);
    putchar('\n');
}
const int hash1 = 23333333;
//const int hash2 = 1e8+7;
const int Mod = 998244353;

const int maxk = 51;
const int maxn = 210000;
const int maxm = 510000;
const int maxs = 1e7+10;

int ph1[maxk+10],ph2[maxk+10];
int s1[maxs],s2[maxs];
void gethash(int x,int y,int &h1,int &h2)
{
    h1=(s1[y]-(ll)s1[x-1]*ph1[y-(x-1)]%hash1+hash1)%hash1;
    h2=s2[y]-(ll)s2[x-1]*ph2[y-(x-1)];
}
struct edge{int y,c;};
vector<edge>V[hash1]; int sum[maxk];
int fi(int h1,int h2)
{
    for(int j=0;j<V[h1].size();j++)
        if(V[h1][j].y==h2) return V[h1][j].c;
}
void ins(int h1,int h2) 
{
    for(int j=0;j<V[h1].size();j++) if(V[h1][j].y==h2) return;
    V[h1].push_back((edge){h2,0});
}
void upd(int h1,int h2,int c)
{
    for(int j=0;j<V[h1].size();j++)
        if(V[h1][j].y==h2) { V[h1][j].c+=c; return; }
}

int n,m;
struct list{int l,r,x;}a[maxn];
int temp[maxk<<2],L,R;

void link(const int x,const int y)
{
    int nowi=x; for(L=maxk;nowi&&maxk-L+1<50;L--,nowi=a[nowi].l) temp[L]=a[nowi].x; L++;
    nowi=y; for(R=maxk+1;nowi&&R-maxk<50;R++,nowi=a[nowi].r) temp[R]=a[nowi].x; R--;

    s1[L-1]=s2[L-1]=0;
    for(int i=L;i<=R;i++) 
    {
        s1[i]=s1[i-1]*11+temp[i]; if(s1[i]>=hash1) s1[i]%=hash1;
        s2[i]=s2[i-1]*23+temp[i];
    }
    for(int l=2;l<maxk;l++) if(sum[l])
    {
        for(int i=max(maxk+2-l,L);i<=maxk&&i+l-1<=R;i++)
        {
            int h1,h2; gethash(i,i+l-1,h1,h2);
            upd(h1,h2,1);
        }
    }
    a[x].r=y; a[y].l=x;
}
void cut(const int x)
{
    int y=a[x].r;
    int nowi=x; for(L=maxk;nowi&&maxk-L+1<50;L--,nowi=a[nowi].l) temp[L]=a[nowi].x; L++;
    nowi=y; for(R=maxk+1;R-maxk<50&&nowi;R++,nowi=a[nowi].r) temp[R]=a[nowi].x; R--;

    s1[L-1]=s2[L-1]=0;
    for(int i=L;i<=R;i++)
    {
        s1[i]=s1[i-1]*11+temp[i]; if(s1[i]>=hash1) s1[i]%=hash1;
        s2[i]=s2[i-1]*23+temp[i];
    }
    for(int l=2;l<maxk;l++) if(sum[l])
    {
        for(int i=max(maxk+2-l,L);i<=maxk&&i+l-1<=R;i++)
        {
            int h1,h2; gethash(i,i+l-1,h1,h2);
            upd(h1,h2,-1);
        }
    }
    a[x].r=0; a[y].l=0;
}

char str[maxs];
int e[maxm][3];
struct node{int h1,h2;};
vector<node>q[maxm];

int main()
{
    ph1[0]=ph2[0]=1;
    for(int i=1;i<maxk+10;i++) ph1[i]=(ll)ph1[i-1]*11%hash1,ph2[i]=(ll)ph2[i-1]*23;

    read(n); read(m);
    for(int i=1;i<=n;i++) read(a[i].x),a[i].l=a[i].r=0;
    for(int i=1;i<=m;i++)
    {
        int t; read(t);
        if(t==1) e[i][0]=1,read(e[i][1]),read(e[i][2]);
        else if(t==2) e[i][0]=2,read(e[i][1]);
        else
        {
            e[i][0]=3;
            scanf("%s",str+1); int len=strlen(str+1);
            int k; read(k); sum[e[i][1]=k]=1;
            int ss00=0,ss01=0,ss10=0,ss11=0;
            for(int j=1;j<=k;j++)
            {
                ss01=ss01*11+str[j]-48; if(ss01>=hash1) ss01%=hash1;
                ss11=ss11*23+str[j]-48;
            }
            for(int j=1;j+k-1<=len;j++)
            {
                int h1=(ss01-(ll)ss00*ph1[k]%hash1+hash1)%hash1;
                int h2=ss11-ss10*ph2[k];
                q[i].push_back((node){h1,h2});
                ins(h1,h2);

                ss00=ss00*11+str[j]-48; if(ss00>=hash1) ss00%=hash1;
                ss01=ss01*11+str[j+k]-48; if(ss01>=hash1) ss01%=hash1;
                ss10=ss10*23+str[j]-48;
                ss11=ss11*23+str[j+k]-48;
            }
        }
    }
    for(int i=1;i<=n;i++) upd(a[i].x,a[i].x,1);
    for(int i=1;i<=m;i++)
    {
        if(e[i][0]==1) link(e[i][1],e[i][2]);
        else if(e[i][0]==2) cut(e[i][1]);
        else
        {
            int re=1;
            for(int j=0;j<q[i].size();j++)
                re=(ll)re*fi(q[i][j].h1,q[i][j].h2)%Mod;
            output(re);
        }
    }

    return 0;
}

T3
令f[i][j]表示寬為j的矩形,下i行保證合法,i+1行存在不合法,這個矩形合法的概率
有f[i][j]=sigma p*f[>i][u]*f[>=i][j-u-1] (列舉不合法的位置,p是前i行合法i+1行不合法的概率)

當i>0時,因為i*j<=K,所以狀態數是K的,暴力轉移是K^2的,可以通過
當i=0時,設計另一個dp,g[i]表示前i個格子的答案,列舉連續的一段f[1]更新,因為中間要用不合法分開不是很方便轉移,不妨令N=n+1,每次在末尾放一個不合法和一段f[1],f[N]/(不合法的概率)即答案
令p為一個格子合法的概率
此時g[i]=sigma g[i-j-1]*(1-p) *f[>=1][j], (j=0 to k)
化成一個常係數齊次遞推式: g[i]=g[i-j]*a[j] (j=1 to k+1)
k<=100時可以直接矩乘
對於更大的資料,考慮優化這個東西
然後叉姐寫過一個東西 《矩陣乘法遞推的優化》 (好像是叫這個
然後學過線性代數的同學還是比較容易看懂的? (看不懂怎麼辦我怎麼知道我也沒看懂啊
弄出這個轉移矩陣的特徵多項式,快速冪求 x^n mod 這個特徵多項式 就可以得到答案了

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define __ %=Mod
using namespace std;

const ll Mod = 998244353;
const int maxn = 2100;

ll pw(ll x,int k)
{
    ll re=1ll;
    for(;k;k>>=1,x=x*x%Mod) if(k&1)
        re=re*x%Mod;
    return re;
}
ll inv(ll x){return pw(x,Mod-2);}

ll temp[maxn];
void sqr(ll f[],int &len)
{
    int ren=len*2;
    for(int i=0;i<=len;i++) temp[i]=f[i];
    for(int i=0;i<=ren;i++) f[i]=0;
    for(int i=0;i<=len;i++)
    {
        for(int j=0;j<=len;j++)
            (f[i+j]+=temp[i]*temp[j]%Mod)__;
    }
    len=ren;
}
void mod(ll A[],int &an,ll B[],int bn)
{
    while(an>=bn)
    {
        int dec=an-bn;
        ll div=A[an]*inv(B[bn]);
        for(int j=0;j<=bn;j++) (A[j+dec]-=B[j]*div%Mod)__;
        while(!A[an]&&an) an--;
    }
}

int n,K; ll p,pi[maxn];
ll f[maxn][maxn],g[maxn][maxn],h[maxn];
ll a[maxn]; int an;
ll s[maxn]; int sn;
int t[maxn],tp;
ll cal()
{
    if(!K) return (pw(1-p,n)*inv(1-p)%Mod+Mod)%Mod;
    memset(f,0,sizeof f); 
    memset(g,0,sizeof g);

    pi[0]=1ll; for(int i=1;i<=K;i++) pi[i]=pi[i-1]*p%Mod;
    for(int i=K;i>=1;i--)
    {
        for(int j=1;i*j<=K;j++)
        {
            ll pp=(pi[i]*(1ll-p)%Mod+Mod)%Mod;
            for(int k=1;k<=j;k++)
            {
                ll t1=(k-1)?g[i+1][k-1]:1;
                ll t2=(k<j)?g[i][j-k]:1;
                (f[i][j]+=t1*t2%Mod*pp%Mod)__;
            }
            g[i][j]=(g[i+1][j]+f[i][j])%Mod;
        }
    }
    g[1][0]=1ll;
    //memset(h,0,sizeof h);
    h[0]=1;
    for(int i=K;i>=0;i--) g[1][i+1]=g[1][i]*(1ll-p)%Mod;
    for(int i=1;i<=K+1;i++)
    {
        h[i]=0;
        for(int j=0;j<i;j++) if(i-j<=K+1) (h[i]+=h[j]*g[1][i-j]%Mod)__;
    }
    //h[i]=h[i-j-1]*(1-p)*g[1][j]     j=0 to k
    //h[k+1]=sigma (1-p)*h[i]*g[1][k-i]
    //x^k+1-sigma (1-p)*g[1][k-i]*x^i=0;


    an=K+2; a[K+2]=1ll;
    for(int i=1;i<=K+1;i++) a[i]=-g[1][K+2-i];

    memset(s,0,sizeof s);
    sn=1; s[1]=1;
    tp=0; for(int now=n;now;t[tp++]=now&1,now>>=1);
    for(int i=tp-2;i>=0;i--)
    {
        sqr(s,sn); 
        if(t[i]) 
        {
            sn++;
            for(int i=sn;i>=1;i--) s[i]=s[i-1];
            s[0]=0;
        }
        mod(s,sn,a,an);
    }
    ll re=0ll;
    for(int i=0;i<=sn;i++) (re+=s[i]*h[i]%Mod)__;
    return (re*inv(1-p)%Mod+Mod)%Mod;
}

int main()
{
    int x,y; scanf("%d%d%d%d",&n,&K,&x,&y); ++n;
    p=(ll)x*inv(y)%Mod;
    ll ans1=cal(); K--;
    ll ans2=cal();
    printf("%lld\n",(ans1-ans2+Mod)%Mod);

    return 0;
}

D2

T1
不考慮有三種選擇的d個地圖,就是裸的2SAT,因為d很小,這d個點其實只有不選A,不選B兩種選擇(不需要再列舉不選C因為前兩種可以覆蓋所有合法情況)
可以2^d列舉d個地圖不選哪個圖,然後跑tarjan的2SAT
跑滿了會T,所以還要加玄學剪枝和隨機優化….

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define id(x,y) x*3-3+y
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 310000;
const int maxm = 210000;

int n,m,d;
int pos[maxn],pn;
struct edge{int y,nex;}a[maxm]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}

int dfn[maxn],low[maxn],id;
int t[maxn],tp; bool insta[maxn];
int bel[maxn],cnt;
void tarjan(const int x)
{
    dfn[x]=low[x]=++id; insta[t[++tp]=x]=true;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
    {
        if(!dfn[y]) tarjan(y),down(low[x],low[y]);
        else if(insta[y]) down(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        ++cnt;
        int la=-1;
        while(la!=x)
        {
            insta[la=t[tp--]]=false;
            bel[la]=cnt;
        }
    }
}

char str[maxn];
int e[maxm][4],oth[maxn];
bool v[maxn];
int chosen[maxn],times;
bool judge()
{
    times++;
    len=0; for(int i=0;i<3*n;i++) fir[i]=0;
    for(int i=1;i<=m;i++)
    {
        int x=e[i][0],y=e[i][2];
        if(v[id(x,e[i][1])])
        {
            if(!v[id(y,e[i][3])]) { x=id(x,e[i][1]); ins(x,oth[x]); continue; }
            x=id(x,e[i][1]),y=id(y,e[i][3]);
            ins(x,y);
            ins(oth[y],oth[x]);
        }
    }
    id=cnt=0; for(int i=0;i<3*n;i++) dfn[i]=low[i]=bel[i]=0,insta[i]=false;
    tp=0; for(int i=0;i<3*n;i++) if(v[i]&&!dfn[i]) tarjan(i);

    for(int i=1;i<=n;i++)
    {
        int x=v[id(i,0)]?id(i,0):id(i,1);
        int y=oth[x];
        if(bel[x]==bel[y]) return false;
        chosen[i]=bel[x]<bel[y]?0:1;
    }
    return true;
}
bool solve(const int now)
{
    if(now>d)
    {
        if(judge()) return true;
        return false;
    }
    int k=pos[now];
    if(times>180) return false;
    if(rand()&1)
    {
        v[id(k,0)]=v[id(k,1)]=true; oth[id(k,0)]=id(k,1); oth[id(k,1)]=id(k,0);
        v[id(k,2)]=false;
        if(solve(now+1)) return true;
        v[id(k,0)]=v[id(k,2)]=true; oth[id(k,0)]=id(k,2); oth[id(k,2)]=id(k,0);
        v[id(k,1)]=false;
        return solve(now+1);
    }
    else
    {
        v[id(k,0)]=v[id(k,2)]=true; oth[id(k,0)]=id(k,2); oth[id(k,2)]=id(k,0);
        v[id(k,1)]=false;
        if(solve(now+1)) return true;
        v[id(k,0)]=v[id(k,1)]=true; oth[id(k,0)]=id(k,1); oth[id(k,1)]=id(k,0);
        v[id(k,2)]=false;
        return solve(now+1);
    }
}

char ss;

int main()
{
    srand(333333);

    read(n); read(d);
    scanf("%s",str);
    memset(v,true,sizeof v);
    for(int i=1;i<=n;i++) 
    {
        if(str[i-1]=='x') pos[++pn]=i;
        else
        {
            int x,y;
            if(str[i-1]=='a') x=id(i,1),y=id(i,2),v[id(i,0)]=false;
            else if(str[i-1]=='b') x=id(i,0),y=id(i,2),v[id(i,1)]=false;
            else x=id(i,0),y=id(i,1),v[id(i,2)]=false;
            oth[x]=y,oth[y]=x;
        }
    }

    read(m);
    for(int i=1;i<=m;i++)
    {
        read(e[i][0]); ss=getchar(); e[i][1]=ss-'A';
        read(e[i][2]); ss=getchar(); e[i][3]=ss-'A';
    }
    if(!solve(1)) return puts("-1"),0;
    for(int i=1;i<=n;i++)
    {
        int x=v[id(i,0)]?id(i,0):id(i,1),d=id(i,0);
        printf("%c",'A'+(chosen[i]==0?x-d:oth[x]-d));
    }

    return 0;
}

T2
有一個不難發現的性質:i天的最優答案選的蔬菜集合一定是i+1天選的蔬菜集合的子集
正解的實質就是模擬費用流過程並用資料結構優化
這題判一種選法是否合法,就是對於任意的t,保質期<=t的蔬菜數<=m*t,用f[n]表示保質期在<=n的蔬菜數,g[n]=f[n]-n*m,當 max g[n] <=0時合法即所有蔬菜都能被賣出
從第1天遞推到第n天,維護一個每種蔬菜的大根堆,貪心的從堆頂依次取m個出來,每種取出其剩餘保質期最大的,線段樹對 [ 保質期,inf ]+1 ,判序列是否合法,不合法就撤銷操作,否則選上這個蔬菜

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n,m,u,K;
int a[maxn],s[maxn],ci[maxn],xi[maxn];
struct segment
{
    int flag,mx;
}seg[maxn<<2];
void pushdown(const int x)
{
    int lc=x<<1,rc=lc|1;
    if(seg[x].flag)
    {
        int fl=seg[x].flag; seg[x].flag=0;
        seg[lc].flag+=fl; seg[lc].mx+=fl;
        seg[rc].flag+=fl; seg[rc].mx+=fl;
    }
}
void pushup(const int x) { seg[x].mx=max(seg[x<<1].mx,seg[x<<1|1].mx); }
void build(const int x,const int l,const int r)
{
    if(l==r) { seg[x].mx=-l*m; return; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    build(lc,l,mid); build(rc,mid+1,r);
    pushup(x);
}
int lx,rx,cc;
void upd(const int x,const int l,const int r)
{
    if(rx<l||r<lx) return;
    if(lx<=l&&r<=rx) { seg[x].flag+=cc; seg[x].mx+=cc; return; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    pushdown(x);
    upd(lc,l,mid); upd(rc,mid+1,r);
    pushup(x);
}
int query(const int x,const int l,const int r)
{
    if(rx<l||r<lx) return -1;
    if(lx<=l&&r<=rx) return seg[x].flag;
    pushdown(x);
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    return max(query(lc,l,mid),query(rc,mid+1,r));
}

struct node{int x,i,ev;};
inline bool operator <(const node x,const node y){return x.x<y.x;}
priority_queue<node>q;

bool judge(const node x)
{
    int oth=ci[x.i]-x.ev;
    int ii=xi[x.i]==0?u:(oth/xi[x.i]+(oth%xi[x.i]?1:0));
    lx=ii,rx=u; cc=1; upd(1,1,u);
    if(seg[1].mx>0) { cc=-1; upd(1,1,u); return false; }
    return true;
}

ll ans[maxn];

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=n;i++) scanf("%d%d%d%d",&a[i],&s[i],&ci[i],&xi[i]);

    u=100000; build(1,1,u);
    for(int i=1;i<=n;i++) q.push((node){a[i]+s[i],i,0});

    ll now=0;
    for(int i=1;i<=u;i++)
    {
        int j=m;
        while(j&&!q.empty())
        {
            node x=q.top(); q.pop();
            if(judge(x))
            {
                j--; now+=x.x;
                x.ev++; x.x=a[x.i];
                if(x.ev!=ci[x.i]) q.push(x);
            }
        }
        ans[i]=now;
        if(q.empty())
        {
            for(int k=i+1;k<=u;k++) ans[k]=now;
            break;
        }
    }

    m=K;
    while(m--)
    {
        int x; scanf("%d",&x);
        printf("%lld\n",ans[x]);
    }

    return 0;
}

T3
聽說把動態凸包的模板弄上去就能get AC
樂滋滋說不可做
uoj好像只有std過了qwq
那我還做這個幹嘛