#13

[CCO2019] Sirtet

题面

首先一个连通块内的点下落的距离相同,令 \(h_{i,j}\) 表示 \((i,j)\) 所在连通块下降的距离,对于一个 \((a,j)\),其中 \(a>i\)\(h_{a,j}\le h_{i,j}\le h_{a,j}+i-a-1\),后面一个不等号取等当且仅当 \((i,j)\) 最后落在 \((a'+1,j)\)

可以发现这是一个差分约束的形式,跑一遍差分约束即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=1e6+10;
int n,m,fa[N],head[N],tot;
vector<bool>a[N],res[N];
int id(int x,int y){
    return (x-1)*m+y;
}
int getfa(int x){
    if(x==fa[x]){
        return x;
    }
    fa[x]=getfa(fa[x]);
    return fa[x];
}
void merge(int u,int v){
    u=getfa(u),v=getfa(v);
    if(u!=v){
        fa[v]=u;
    }
}
struct edge{
    int v,w,nxt;
}e[N<<2];
void add(int u,int v,int w){
    u=getfa(u),v=getfa(v);
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
    // cerr<<head[u]<<endl;
}
int dis[N],vis[N];
void dij(){
    priority_queue<pii>q;
    for(int i=1;i<=n*m;i++){
        dis[i]=inf;
    }
    q.push(mp(0,0));
    while(q.size()){
        int u=q.top().second;
        // cerr<<u<<endl;
        q.pop();
        if(vis[u]){
            continue;
        }
        vis[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].v,w=e[i].w;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                q.push(mp(-dis[v],v));
            }
        }
    }
}
void solve(){
    read(n),read(m);
    a[0].resize(m+10);
    a[n+1].resize(m+10);
    for(int i=1;i<=n;i++){
        a[i].resize(m+10);
        res[i].resize(m+10);
        for(int j=1;j<=m;j++){
            char opt=getchar();
            while(opt!='.'&&opt!='#'){
                opt=getchar();
            }
            a[i][j]=(opt=='#');
        }
    }
    for(int i=1;i<=n*m;i++){
        fa[i]=i;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!a[i][j]){
                continue;
            }
            if(a[i-1][j]){
                merge(id(i,j),id(i-1,j));
            }
            if(a[i][j-1]){
                merge(id(i,j),id(i,j-1));   
            }
            if(a[i+1][j]){
                merge(id(i,j),id(i+1,j));
            }
            if(a[i][j+1]){
                merge(id(i,j),id(i,j+1));
            }
        }
    }
    for(int j=1;j<=m;j++){
        int lst=-1;
        for(int i=1;i<=n;i++){
            if(a[i][j]){
                if(lst!=-1){
                    add(id(i,j),id(lst,j),i-lst-1);
                }
                lst=i;
            }
            if(lst!=-1){
                add(0,id(lst,j),n-lst);
            }
        }
    }
    dij();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]){
                res[i+dis[getfa(id(i,j))]][j]=1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            putchar(res[i][j]?'#':'.');
        }
        putchar('\n');
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

MEX counting

题面

第二个条件,其实是限制每个前缀 \(mex\) 都要处于一个区间内。令 \(f_{i,j,k}\) 表示 \([1,i]\)\(mex\)\(k\),恰有 \(j\) 个不同的大于 \(k\) 的数。

分类讨论转移:

  1. \(a_i\le k\)\(f_{i,j,k}\times k\rightarrow f_{i+1,j,k}\)
  2. \(a_i\) 是已经出现过的大于 \(k\) 的数,\(f_{i,j,k}\times j\rightarrow f_{i+1,j,k}\)
  3. \(a_i\) 是未出现过的大于 \(k\) 的数,\(f_{i,j,k}\rightarrow f_{i+1,j+1,k}\)
  4. \(a_i=k\),设此时的 \(mex\)\(x\)\(j>x-k-1\)\(A^j_{x-k-1}f_{i,j,k}\rightarrow f_{i+1,j-x+k+1,x}\)

这里状态是 \(O(n^2k)\),转移是 \(O(n)\) 的,考虑优化这个转移。

将转移 \(4\) 的式子拆开,\(\frac{j!}{(j-x+k+1)}f_{i,j,k}\rightarrow f_{i+1,j-x+k+1,x}\),令 \(j'=j-x+k+1\),转移式变为了 \(\frac{j!}{j'!}f_{i,j,k}\rightarrow f_{i,j',x}\),转移系数变成了两个 \(j\) 的阶乘相除。

\(j=j+k,j'=j'+x\)\(A^{j-k}_{j+1-x}f_{i,j,k}\rightarrow f_{i,j',x}\),根据上面得出的,转移系数的分母应当是后面 dp 状态中的 \(j\),所以 \(j'=j+1\),可以前缀和转移。这样所有转移的复杂度均为 \(O(1)\) 了,总复杂度 \(O(n^2k)\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e3+10,K=110,mod=998244353;
int n,k,mn[N],mx[N],f[2][N][N],s[2][N][N],fac[N],inv[N];
int qpow(int a,int b){
    int res=1;
    while(b){
        if(b&1){
            res=1ll*res*a%mod;
        }
        b>>=1;
        a=1ll*a*a%mod;
    }
    return res;
}
void init(int MX){
    fac[0]=1;
    for(int i=1;i<=MX;i++){
        fac[i]=1ll*fac[i-1]*i%mod;
    }
    inv[MX]=qpow(fac[MX],mod-2);
    for(int i=MX-1;i>=0;i--){
        inv[i]=1ll*inv[i+1]*(i+1)%mod;
    }
}
void solve(){
    init(2000);
    // for(int i=1;i<=10;i++){
    //     cerr<<fac[i]<<' '<<inv[i]<<endl;
    // }
    read(n),read(k);
    for(int i=1,x;i<=n;i++){
        read(x);
        mn[i]=max(0,x-k);
        mx[i]=min(i,x+k);
    }
    f[0][0][0]=s[0][0][0]=1;
    for(int i=1,opt=1;i<=n;i++,opt^=1){
        for(int j=0;j<=i;j++){
            for(int k=mn[i];k<=mx[i]&&k<=j;k++){
                f[opt][j][k]=(f[opt][j][k]+1ll*f[opt^1][j][k]*j%mod)%mod;
                if(j){
                    f[opt][j][k]=(f[opt][j][k]+f[opt^1][j-1][k])%mod;
                }
                if(j&&k){
                    f[opt][j][k]=(f[opt][j][k]+1ll*s[opt^1][j-1][min(k-1,mx[i-1])]*inv[j-k]%mod)%mod;
                }
                s[opt][j][k]=1ll*f[opt][j][k]*fac[j-k]%mod;
                if(k){
                    s[opt][j][k]=(s[opt][j][k]+s[opt][j][k-1])%mod;
                }
            }
        }
        for(int j=0;j<i;j++){
            for(int k=mn[i-1];k<=mx[i-1]&&k<=j;k++){
                s[opt^1][j][k]=f[opt^1][j][k]=0;
            }
        }
    }
    int ans=0;
    for(int i=0;i<=n;i++){
        for(int j=mn[n];j<=mx[n]&&j<=i;j++){
            ans=(ans+1ll*f[n&1][i][j]*fac[n-j]%mod*inv[n-i]%mod)%mod;
        }
    }
    write_endl(ans);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

[AGC015E] Mr.Aoki Incubator

题面

\(S_A\) 表示集合 \(A\) 最终染色得到的节点,\(S_{A\cup B}=S_A\cup S_B\),证明容易,将染色看作一条边,从染色点连向被染色点,从 \(0\) 连向初始染色点,\(S_A,S_B\) 相当于一棵树,\(S_{A\cup B}\) 相当于两棵树的并,这启示我们将点可以分开考虑。

将所有点以 \(x\) 为关键字排序,\(mx_i\) 表示前缀速度最大值,\(mn_i\) 表示后缀速度最小值。令 \(f_i\) 表示染色 \([1,i]\),且初始染 \(i\) 的方案数。假定上一个染色的是 \(j\),覆盖不到的点就是位置在 \([j+1,i-1]\),速度在 \([mx_j,mn_i]\) 中的点,显然如果成功转移,就不应该存在这样的点。可以双指针维护转移区间与这样的点的数量,用前缀和转移即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10,mod=1e9+7;
int n,val[N],mx[N],mn[N],pos[N],f[N],s[N],sum,l,r=-1,L,R=-1;
struct point{
    int x,y;
}p[N];
bool cmp(point x,point y){
    return x.x<y.x;
}
bool check(int q_l,int q_r,int q_L,int q_R){
    if(q_l>q_r||q_L>q_R){
        return 0;
    }
    while(l<q_l){
        sum-=(p[l].y>=L&&p[l].y<=R);
        l++;
    }
    while(r<q_r){
        r++;
        sum+=(p[r].y>=L&&p[r].y<=R);
    }
    while(L<q_L){
        sum-=(pos[L]>=l&&pos[L]<=r);
        L++;
    }
    while(R<q_R){
        R++;
        sum+=(pos[R]>=l&&pos[R]<=r);
    }
    return sum;
}
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(p[i].x),read(p[i].y);
        val[i]=p[i].y;
    }
    // cerr<<"HAHA"<<endl;
    sort(val+1,val+n+1);
    for(int i=1;i<=n;i++){
        p[i].y=lower_bound(val+1,val+n+1,p[i].y)-val;
    }
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++){
        mx[i]=max(mx[i-1],p[i].y);
    }
    mn[n+1]=n+1;
    for(int i=n;i;i--){
        mn[i]=min(mn[i+1],p[i].y);
    }
    for(int i=1;i<=n;i++){
        pos[p[i].y]=i;
    }
    f[0]=s[0]=1;
    int now=0;
    for(int i=1;i<=n+1;i++){
        while(check(now+1,i-1,mx[now],mn[i])){
            now++;
        }
        f[i]=s[i-1];
        if(now){
            f[i]=(f[i]+mod-s[now-1])%mod;
        }
        s[i]=(s[i-1]+f[i])%mod;
    }
    write_endl(f[n+1]);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

[HNOI2013] 切糕

题面

将两个条件分开处理,第一个条件相当于对于每一列建一条长度为 \(R+1\) 的链,从 \((i,j,k)\)\((i,j,k+1)\) 连一条流量为 \(v_{i,j,k}\) 的边,从 \(S\)\((i,j,1)\) 连一条流量为 \(+\infty\) 的边,从 \((i,j,R+1)\)\(T\) 连一条流量为 \(+\infty\) 的边,这样 \(S\)\(T\) 的最小割就是最小权值和。

接下来处理出第二个条件,拆开式子 \(-D\le f(x,y)-f(x',y')\le D\)。因为反过来是一样的,所以只需要管 \(f(x,y)-f(x',y')\le D\)。这个很好处理,连一条 \((x,y,f(x,y))\)\((x',y',f(x,y)-d)\) 连边,这样如果差值大于 \(d\),则需要多割边,更劣。答案为该图的最小割。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e18;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=4e5+10,Siz=50;
int tot=1,head[N],v[Siz][Siz][Siz],P,Q,R,d,S,T;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
struct edge{
    int v,w,nxt;
}e[N];
void add(int u,int v,int w){
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void add_e(int u,int v,int w){
    add(u,v,w);
    add(v,u,0);
}
int id(int x,int y,int z){
    return (z-1)*P*Q+(x-1)*Q+y;
}
namespace Max_Flow{
    int cur[N<<1],dep[N<<1];
    bool bfs(){
        queue<int>q;
        for(int i=1;i<=T;i++){
            dep[i]=0;
        }
        dep[S]=1;
        q.push(S);
        while(!q.empty()){
            int u=q.front();
            // cerr<<u<<endl;
            q.pop();
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].v,w=e[i].w;
                if(!dep[v]&&w){
                    dep[v]=dep[u]+1;
                    if(v==T){
                        return 1;
                    }
                    q.push(v);
                }
            }
        }
        return 0;
    }
    int dfs(int u,int flow){
        if(u==T){
            return flow;
        }
        int ans=0;
        for(int i=cur[u];i;i=e[i].nxt){
            cur[u]=i;
            int v=e[i].v,w=e[i].w;
            if(dep[v]==dep[u]+1&&w){
                int res=dfs(v,min(flow,w));
                e[i].w-=res;
                e[i^1].w+=res;
                flow-=res;
                ans+=res;
            }
            if(!flow){
                break;
            }
        }
        if(!ans){
            dep[u]=0;
        }
        return ans;
    }
    int dinic(){
        int ans=0;
        while(bfs()){
            // cerr<<"AHA"<<endl;
            for(int i=1;i<=T;i++){
                cur[i]=head[i];
            }
            ans+=dfs(S,inf);
        }
        return ans;
    }
}
void solve(){
    read(P),read(Q),read(R),read(d);
    S=id(P,Q,R+1)+1,T=id(P,Q,R+1)+2;
    for(int i=1;i<=R;i++){
        for(int j=1;j<=P;j++){
            for(int k=1;k<=Q;k++){
                read(v[j][k][i]);
            }
        }
    }
    for(int i=1;i<=P;i++){
        for(int j=1;j<=Q;j++){
            add_e(S,id(i,j,1),inf);
            add_e(id(i,j,R+1),T,inf);
            for(int k=1;k<=R;k++){
                add_e(id(i,j,k),id(i,j,k+1),v[i][j][k]);
            }
        }
    }
    for(int i=1;i<=P;i++){
        for(int j=1;j<=Q;j++){
            for(int way=0;way<4;way++){
                int x=i+dx[way],y=j+dy[way];
                if(x<1||y<1||x>P||y>Q){
                    continue;
                }
                for(int k=d+1;k<=R+1;k++){
                    add_e(id(i,j,k),id(x,y,k-d),inf);
                }
            }
        }
    }
    write_endl(Max_Flow::dinic());
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

[COCI2015] Divljak

题面

注意到询问是一个多模匹配问题,对于所有的串建出AC自动机。

对于一个新的串 \(P\),它能对集合中哪些 \(S\) 造成贡献。考虑匹配这个过程,相当于匹配到若干个点,将它一直往上跳 \(fail\) 的一段路径上点对应的串 \(+1\)。这是一个路径加,单点查询的过程。使用树上差分,可以变为单点加,子树查询,用树状数组维护即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10,S=2e6+10;
int n,m,cnt,idx=1,flag[N];
string s[N];
struct node{
    int ch[26],fail;
}p[S];
void insert(string s,int id){
    int now=1,len=s.size();
    for(int i=0;i<len;i++){
        if(!p[now].ch[s[i]-'a']){
            p[now].ch[s[i]-'a']=++idx;
        }
        now=p[now].ch[s[i]-'a'];
    }
    flag[id]=now;
}
void get_fail(){
    for(int i=0;i<26;i++){
        p[0].ch[i]=1;
    }
    queue<int>q;
    q.push(1);
    p[1].fail=0;
    while(q.size()){
        int u=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            if(!p[u].ch[i]){
                p[u].ch[i]=p[p[u].fail].ch[i];
            }
            else{
                p[p[u].ch[i]].fail=p[p[u].fail].ch[i];
                q.push(p[u].ch[i]);
            }
        }
    }
}
vector<int>e[S];
int siz[S],dep[S],heavy[S],dfn[S],top[S],fa[S];
void make_tree(int u){
    siz[u]=1;
    for(auto v:e[u]){
        dep[v]=dep[u]+1;
        make_tree(v);
        siz[u]+=siz[v];
        fa[v]=u;
        if(siz[v]>siz[heavy[u]]){
            heavy[u]=v;
        }
    }
}
void dfs(int u,int topf){
    dfn[u]=++dfn[0];
    top[u]=topf;
    if(heavy[u]){
        dfs(heavy[u],topf);
    }
    for(auto v:e[u]){
        if(v==heavy[u]){
            continue;
        }
        dfs(v,v);
    }
}
int lca(int u,int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]){
            swap(u,v);
        }
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]){
        swap(u,v);
    }
    return u;
}
bool cmp(int x,int y){
    return dfn[x]<dfn[y];
}
namespace Fenwick_Tree{
    int c[S];
    int lowbit(int x){
        return x&(-x);
    }
    void update(int pos,int val){
        while(pos<=idx){
            c[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int query(int pos){
        int res=0;
        while(pos){
            res+=c[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
}
int pos[S];
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        cin>>s[++cnt];
        insert(s[cnt],cnt);
    }
    get_fail();
    for(int i=2;i<=idx;i++){
        e[p[i].fail].pb(i);
    }
    dep[1]=1;
    make_tree(1);
    dfs(1,1);
    read(m);
    while(m--){
        int opt,x;
        read(opt);
        if(opt==1){
            cin>>s[++cnt];
            int now=1,len=s[cnt].size();
            s[cnt]=' '+s[cnt];
            for(int i=1;i<=len;i++){
                now=p[now].ch[s[cnt][i]-'a'];
                pos[i]=now;
            }
            sort(pos+1,pos+len+1,cmp);
            for(int i=1;i<=len;i++){
                Fenwick_Tree::update(dfn[pos[i]],1);
            }
            for(int i=1;i<len;i++){
                Fenwick_Tree::update(dfn[lca(pos[i],pos[i+1])],-1);
            }
        }
        else{
            read(x);
            int p=flag[x];
            write_endl(Fenwick_Tree::query(dfn[p]+siz[p]-1)-Fenwick_Tree::query(dfn[p]-1));
        }
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2023-10-09 20:58  luo_shen  阅读(20)  评论(0编辑  收藏  举报