In mathematics you don't understand things, you just get used to them.

标签 maths 下的文章

「CF 1514A」Perfectly Imperfect Array

Link.

就看序列中是否存在不为平方数的元素即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
ll T,n,x;
bool check(ll x)
{
    for(ll i=1;i*i<=x;++i)    if(i*i==x)    return true;
    return false;
}
int main()
{
    for(sf(T);T;--T)
    {
        sf(n);
        bool fl=0;
        for(int i=1;i<=n;++i)
        {
            sf(x);
            if(!check(x))    fl=1;
        }
        if(fl)    puts("YES");
        else    puts("NO");
    }
    return 0;
}

「CF 1514B」AND 0, Sum Big

Link.

和最大的情况就是每个数都只有一个 $0$(二进制下),于是答案就是 $n^{k}$。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
const int MOD=1e9+7;
int main()
{
    int T,n,k;
    for(sf(T);T;--T)
    {
        sf(n),sf(k);
        ll ans=1;
        for(int i=1;i<=k;++i)    ans*=n,ans%=MOD;
        pf(ans);
    }
    return 0;
}

「CF 1514C」Product 1 Modulo N

Link.

把所有与 $n$ 互质的数拉出来,如果 product 不满足要求,就把最后一个剔除。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int n;
ll op(ll x,ll y){return x*y%n;}
int main()
{
    sf(n);
    std::vector<ll> ans;
    for(int i=1;i<=n;++i)    if(__gcd(i,n)==1)    ans.emplace_back(i);
    if(accumulate(ans.begin(),ans.end(),1,op)!=1)    ans.pop_back();
    pf(ans.size());
    for(int i:ans)    pf(i,' ');
    return 0;
}

「CF 1514D」Cut and Stick

Link.

答案是 $\max\{1,2x-l\}$,$l$ 为区间长度,$x$ 为众数出现次数。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int MAXN = 5e5 + 5, MAXM = 720 + 5;

char buf[1 << 21], *p1 = buf, *p2 = buf;
#define getchar( ) ( p1 == p2 && ( p2 = ( p1 = buf ) + fread( buf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1 ++ )

template<typename _T>
void read( _T &x ){
    x = 0; char c = getchar( ); _T f = 1;
    while( c < '0' || c > '9' ){ if( c == '-' )    f = -1; c = getchar( ); }
    while( c >= '0' && c <= '9' ){ x = ( x << 3 ) + ( x << 1 ) + ( c & 15 ); c = getchar( ); }
    x *= f;
}

template<typename _T>
void write( _T x ){
    if( x < 0 ){ putchar( '-' ); x = -x; }
    if( x > 9 ){ write( x / 10 ); }
    putchar( x % 10 + '0' );
}

template<typename _T>
void swapp( _T &one, _T &another ){ int temp = one; one = another; another = temp; }

template<typename _T>
_T MIN( _T one, _T another ){ return one > another ? another : one; }

template<typename _T>
_T MAX( _T one, _T another ){ return one > another ? one : another; }

int N, M;
int cube, each, kase, isa[MAXN], cnt[MAXN], pos[MAXN], vis[MAXN], bel[MAXN];
int lps[MAXM], rps[MAXM], App[MAXM][MAXM];
vector<int> disc, fur[MAXN];

int getID( int x ){ return lower_bound( disc.begin( ), disc.end( ), x ) - disc.begin( ) + 1; }

void build( ){
    memset( cnt, 0, sizeof( cnt ) );
    for( int i = 1; i <= cube; ++ i ){
        kase ++;
        for( int j = i; j <= cube; ++ j ){
            App[i][j] = App[i][j - 1];
            for( int k = lps[j]; k <= rps[j]; ++ k ){
                if( vis[isa[k]] != kase )    cnt[isa[k]] = 0;
                cnt[isa[k]] ++; App[i][j] = MAX( App[i][j], cnt[isa[k]] );
                vis[isa[k]] = kase;
            }
        }
    }
    memset( cnt, 0, sizeof( cnt ) );
}

int query( int opl, int opr ){
    if( bel[opl] == bel[opr] ){
        int res = 0; kase ++;
        for( int i = opl; i <= opr; ++ i ){
            if( vis[isa[i]] != kase )    cnt[isa[i]] = 0;
            cnt[isa[i]] ++; res = MAX( res, cnt[isa[i]] );
            vis[isa[i]] = kase;
        }
        return res;
    }
    int res = 0;
    res = App[bel[opl] + 1][bel[opr] - 1];
    for( int i = opl; i <= rps[bel[opl]]; ++ i ){
        int lim = fur[isa[i]].size( ) - 1;
        while( pos[i] + res <= lim && fur[isa[i]][pos[i] + res] <= opr )    res ++;
    }
    for( int i = lps[bel[opr]]; i <= opr; ++ i ){
        while( pos[i] - res >= 0 && fur[isa[i]][pos[i] - res] >= opl )    res ++;
    }
    return res;
}

signed main( ){
    read( N ); read( M ); each = 720; cube = ( N - 1 ) / each + 1;
    for( int i = 1; i <= N; ++ i ){ read( isa[i] ); disc.push_back( isa[i] ); }
    sort( disc.begin( ), disc.end( ) );
    disc.erase( unique( disc.begin( ), disc.end( ) ), disc.end( ) );
    for( int i = 1; i <= N; ++ i ){
        isa[i] = getID( isa[i] );
        fur[isa[i]].push_back( i );
        pos[i] = fur[isa[i]].size( ) - 1;
    }
    for( int i = 1; i <= cube; ++ i ){
        lps[i] = rps[i - 1] + 1; rps[i] = rps[i - 1] + each;
        if( i == cube )    rps[i] = N;
        for( int j = lps[i]; j <= rps[i]; ++ j )    bel[j] = i;
    }
    build( );
    int opl, opr;
    while( M -- > 0 ){
        read( opl ); read( opr );
        write( max( 1, 2 * query( opl, opr ) - ( opr - opl + 1 ) ) );
        putchar( '\n' );
    }
    return 0;
}

「CF 1514E」Baby Ehab's Hyper Apartment

Link.

// Oops, something went wrong.

「CF 1525A」Potion-making

Link.

显然。

#include<bits/stdc++.h>
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int gcd(int x,int y){return !y?x:gcd(y,x%y);}
int main()
{
    int T,k;
    sf(T);
    while(T-->0)
    {
        sf(k);
        int p1=k,p2=100-k,x=gcd(p1,p2);
        p1/=x;
        p2/=x;
        pf(p1+p2);
    }
    return 0;
}

「CF 1525B」Permutation Sort

Link.

注意到答案只有 $0/1/2/3$,分类讨论即可。

吃了三发罚时

#include<bits/stdc++.h>
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int T,n,a[60];
int main()
{
    for(sf(T);T;--T)
    {
        sf(n);
        for(int i=1;i<=n;++i)    sf(a[i]);
        int flag=1;
        for(int i=2;i<=n;++i)
        {
            if(a[i]!=a[i-1]+1)
            {
                flag=0;
                break;
            }
        }
        if(!flag)
        {
            if(a[1]==n && a[n]==1)    puts("3");
            else if(a[n]==n || a[1]==1)    puts("1");
            else    puts("2");
        }
        else    puts("0");
    }
    return 0;
}

「CF 1525C」Robot Collisions

Link.

显然我不会。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mp make_pair
template<typename T>void sf(T &x) {
    x = 0;
    T f = 0;
    char c = getchar();

    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-')
            f = 1;

    for (; c >= '0' && c <= '9'; c = getchar())
        x = (x << 3) + (x << 1) + (c^'0');

    if (f)
        x = -x;
}
template<typename T>void pf(T x, char l = '\n') {
    static T s[100], t;

    if (x < 0)
        putchar('-'), x = -x;

    do
        s[++t] = x % 10, x /= 10;

    while (x)
        ;

    while (t)
        putchar(s[t--]^'0');

    putchar(l);
}
struct st {
    int a, b, id;
} Sts[300005], Uji[300005], Qql[300005];
bool cmp(st A, st B) {
    return A.a < B.a;
}
int reait[300005];
int n, m;
int U(int x, int y) {
    int res = 0;

    if (Sts[x].a < Sts[y].a) {
        if (Sts[x].b == 0)
            res += Sts[x].a, Sts[x].a = 0;

        if (Sts[y].b == 1)
            res += (m - Sts[y].a), Sts[y].a = m;

        return (res + abs(Sts[x].a - Sts[y].a)) / 2;
    } else {
        if (Sts[x].b == 1)
            res += (m - Sts[x].a), Sts[x].a = m;

        if (Sts[y].b == 0)
            res += Sts[y].a, Sts[y].a = 0;

        return (res + abs(Sts[x].a - Sts[y].a)) / 2;
    }
}
signed main() {
    int T;
    sf(T);

    while (T--) {
        sf(n), sf(m);

        for (int i = 1; i <= n; i++)
            reait[i] = -1;

        int rks = 0, tss = 0;

        for (int i = 1; i <= n; i++) {
            sf(Sts[i].a);
            Sts[i].id = i;
        }

        for (int i = 1; i <= n; i++) {
            char res = getchar();

            while (res != 'L' && res != 'R')
                res = getchar();

            Sts[i].b = res == 'R';
        }

        for (int i = 1; i <= n; i++) {
            if (Sts[i].a & 1)
                Qql[++tss] = Sts[i];
            else
                Uji[++rks] = Sts[i];
        }

        sort(Uji + 1, Uji + rks + 1, cmp);
        sort(Qql + 1, Qql + tss + 1, cmp);
        stack <int> Q;
        Q.push(1);

        for (int i = 2; i <= rks; i++) {
            if (Uji[i].b == 0 && !Q.empty()) {
                int u = Q.top();
                Q.pop();
                reait[Uji[i].id] = reait[Uji[u].id] = U(Uji[i].id, Uji[u].id);
            } else
                Q.push(i);
        }

        while (!Q.empty()) {
            int u = Q.top();
            Q.pop();

            if (!Q.empty()) {
                int v = Q.top();
                Q.pop();
                reait[Uji[u].id] = reait[Uji[v].id] = U(Uji[u].id, Uji[v].id);
            }
        }

        Q.push(1);

        for (int i = 2; i <= tss; i++) {
            if (Qql[i].b == 0 && !Q.empty()) {
                int u = Q.top();
                Q.pop();
                reait[Qql[i].id] = reait[Qql[u].id] = U(Qql[i].id, Qql[u].id);
            } else
                Q.push(i);
        }

        while (!Q.empty()) {
            int u = Q.top();
            Q.pop();

            if (!Q.empty()) {
                int v = Q.top();
                Q.pop();
                reait[Qql[u].id] = reait[Qql[v].id] = U(Qql[u].id, Qql[v].id);
            }
        }

        for (int i = 1; i <= n; i++)
            printf("%lld ", reait[i]);

        printf("\n");
    }

    return 0;
}

「CF 1525D」Armchairs

Link.

设 $f(i,j)$ 表示考虑把第 $j$ 个人放进前 $i$ 个座位里的方案,转移。

多久没写 DP 了啊,这种水平的 DP 都写漏一堆东西。

#include<bits/stdc++.h>
typedef long long ll;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static T s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int n,a[5010],fr[5010],t0,oc[5010],t1,op[5010];
ll dp[5010][5010],ans=std::numeric_limits<ll>::max();
inline int fs(int x){return x<0?-x:x;}
int main()
{
    sf(n);
    for(int i=1;i<=n;++i)
    {
        sf(a[i]);
        if(a[i])    oc[++t1]=i;
        else    fr[++t0]=i;
    }
    for(int i=1;i<=t1;++i)    for(int j=0;j<=n;++j)    dp[i][j]=1e18;
    for(int i=1;i<=t1;++i)    for(int j=1;j<=n;++j) {
        dp[i][j]=dp[i][j-1];
        if(!a[j])    dp[i][j]=std::min(dp[i][j],dp[i-1][j-1]+fs(oc[i]-j));
    }
    pf(dp[t1][n]);
    return 0;
}

「CF 1525E」Assimilation IV

Link.

// Oops, something went wrong.

「CF 1525F」Goblins And Gnomes

Link.

// Oops, something went wrong.

Description

Link.

求 $\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^kf(\gcd(i,j))\gcd(i,j)$。

Solution

$$ \begin{aligned} \textbf{ANS}&=\sum_{i=1}^{n}\sum_{j=1}^{n}(i+j)^{k}\mu^{2}(\gcd(i,j))\gcd(i,j) \\ &=\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{n}(i+j)^{k}\mu^{2}(d)d[\gcd(i,j)=d] \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}(i+j)^{k}\sum_{h|i,h|j}\mu(h) \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{h=1}^{\lfloor\frac{n}{d}\rfloor}\mu(h)\times h^{k}\times\sum_{i=1}^{\lfloor\frac{n}{dh}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{dh}\rfloor}(i+j)^{k} \\ &=\sum_{d=1}^{n}d^{k+1}\times\mu^{2}(d)\sum_{h=1}^{\lfloor\frac{n}{d}\rfloor}\mu(h)\times h^{k}\times\sum_{i=1}^{\lfloor\frac{n}{dh}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{dh}\rfloor}(i+j)^{k} \\ \end{aligned} \\ $$

前面两个和式里面显然能算,考虑怎么对于 $x$ 算 $\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k}$。考虑对其差分:

$$ \begin{aligned} \left(\sum_{i=1}^{x+1}\sum_{j=1}^{x+1}(i+j)^{k}\right)-\left(\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k}\right)&=\sum_{i=1}^{x}\sum_{j=1}^{x+1}(i+j)^{k}+\sum_{i=1}^{x+1}(x+1+i)^{k}-\sum_{i=1}^{x}\sum_{j=1}^{x}(i+j)^{k} \\ &=\sum_{i=1}^{x}\left(\sum_{j=1}^{x+1}(i+j)^{k}-\sum_{j=1}^{x}(i+j)^{k}\right)+\sum_{i=1}^{x+1}(x+1+i)^{k} \\ &=\sum_{i=1}^{x}(x+1+i)^{k}+\sum_{i=1}^{x+1}(x+1+i)^{k} \\ \end{aligned} $$

然后滚个前缀和就可以算了。

#include<bits/stdc++.h>
typedef long long LL;
const int MOD=998244353;
int norm( LL x ) {
    if( x<0 ) {
        x+=MOD;
    }
    if( x>=MOD ) {
        x%=MOD;
    }
    return x;
}
int n,k,ans;
int qpow( int bas,int fur ) {
    int res=1;
    while( fur ) {
        if( fur&1 ) {
            res=norm( LL( res )*bas );
        }
        bas=norm( LL( bas )*bas );
        fur>>=1;
    }
    return norm( res+MOD );
}
std::tuple<std::vector<int>,std::vector<int>> makePrime( int n ) {
    std::vector<int> prime,tag( n+1 ),mu( n+1 ),pw( n+1 );
    pw[0]=1;
    mu[1]=pw[1]=1;
    for( int i=2;i<=n;++i ) {
        if( !tag[i] ) {
            mu[i]=norm( -1 );
            prime.emplace_back( i );
            pw[i]=qpow( i,k );
        }
        for( int j=0;j<int( prime.size() ) && i*prime[j]<=n;++j ) {
            tag[i*prime[j]]=1;
            pw[i*prime[j]]=norm( LL( pw[i] )*pw[prime[j]] );
            if( i%prime[j]==0 ) {
                mu[i*prime[j]]=0;
                break;
            } else {
                mu[i*prime[j]]=norm( -mu[i] );
            }
        }
    }
    return std::tie( mu,pw );
}
int main() {
    LL tmp;
    scanf( "%d %lld",&n,&tmp );
    k=tmp%( MOD-1 );
    std::vector<int> mu,pw,prt( n+1 ),exprt( n+1 ),preSum( n+1 );
    // prt: i^(k+1)*mu^2(i)
    // exprt: mu(i)*i^k
    // preSum sum sum (i+j)^k
    std::tie( mu,pw )=makePrime( n<<1|1 );
    for( int i=1;i<=n;++i ) {
        prt[i]=norm( prt[i-1]+norm( LL( norm( LL( norm( LL( mu[i] )*mu[i] ) )*pw[i] ) )*i ) );
        exprt[i]=norm( exprt[i-1]+norm( LL( mu[i] )*pw[i] ) );
    }
    for( int i=1;i<=( n<<1 );++i ) {
        pw[i]=norm( pw[i]+pw[i-1] );
    }
    for( int i=1;i<=n;++i ) {
        preSum[i]=norm( norm( preSum[i-1]+norm( pw[i<<1]-pw[i] ) )+norm( pw[(i<<1)-1]-pw[i] ) );
    }
    for( int l=1,r;l<=n;l=r+1 ) {
        r=n/( n/l );
        int tmp=0;
        for( int exl=1,exr,m=n/l;exl<=m;exl=exr+1 ) {
            exr=m/( m/exl );
            tmp=norm( tmp+norm( LL( norm( exprt[exr]-exprt[exl-1] ) )*preSum[m/exl] ) );
        }
        ans=norm( ans+LL( norm( prt[r]-prt[l-1] ) )*tmp );
    }
    printf("%d\n",ans);
    return 0;
}

本文差不多算是翻译了一遍 CF blog?id=45223 就是抄了一遍,看不懂可以去原文。

当然我的翻译并不是完全遵从原文的。

Part. 1 Introduction

平时我们怎么求高维前缀和?容斥对吧,复杂度多少?$\mathcal{O}(n^{d}\times2^{d})$($n$ 每维元素个数,默认同阶,$d$ 维度)。

这好吗?这不好。

Part. 2 Ying Wen

For 个 example,二维,容斥这么写对吧?

for(int i=1;i<=n;i++)
{
  for(int j=1;j<=n;j++)  f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j];
}

事实上我们还可以分维来前缀和:

for(int i=1;i<=n;i++)
{
  for(int j=1;j<=n;j++)  f[i][j]=f[i-1][j]+a[i][j];
}
for(int i=1;i<=n;i++)
{
  for(int j=1;j<=n;++j)  f[i][j]=f[i][j-1]+a[i][j];;
}

复杂度多少?$\mathcal{O}(n^{d}\times d)$,厉害吧。

对应到 SOS DP(sum over subsets),我们把每一维整到集合上去来求子集和。

形式化地定义子集和,即给定一个有 $2^{n}$ 个元素的数组 $A$,定义函数:

$$ \text{sub-sum}(mask)=\sum_{i\subseteq mask}A_{i} $$

写成位运算的形式:

$$ \text{sub-sum}(mask)=\sum_{mask\text{ & }i=i}A_{i} $$

学过 FWT 的巨佬可能发现了什么,可是这和我没关系。

看不懂?没关系,我们有严谨的代码定义:

for(int mask = 0;mask < (1<<N); ++mask){
    for(int i = 0;i < (1<<N); ++i){
        if((mask&i) == i){
            F[mask] += A[i];
        }
    }
}

这是什么垃圾复杂度,用高维前缀和可得以下代码:

for (int j = 0; j < n; ++j) {
  for (int i = 0; i < (1 << n); ++i) {
    if((i >> j) & 1)  f[i] += f[i ^ (1 << j)];
  }
}

Description

Link.

给出一个带权无向图,边权为 $2^{a}\cdot3^{b}$ 形式。

给出 $q$ 组形如 $u,v,a,b$ 的询问,问 $u,v$ 中是否存在一条路径使得其边权之 $\text{lcm}$ 为 $2^{a}\cdot3^{b}$。

Solution

考虑 $\text{lcm}$ 的本质,对 $n$ 个数 $\prod_{i=1}^{k_{1}}p_{1,i}^{c_{1,i}},\prod_{i=1}^{k_{2}}p_{2,i}^{c_{2,i}},\dots,\prod_{i=1}^{k_{n}}p_{n,i}^{c_{n,i}}$ 取 $\text{lcm}$ 就是 $\prod_{i=1}^{\max\{k\}}p_{i}^{\max\{c\}}$(在一个数中存在的 $p$ 且在另一个中不存在的置为 $1$),对于这题即 $2^{\max\{a\}}\cdot 3^{\max\{b\}}$,让两个 $\max$ 分别等于题目给出的 $a,b$。

现在转化一下题意,在 $u,v$ 中选出一条可非简单路径使得 $\max\{a\},\max\{b\}$ 分别等于给出的 $a,b$。

有一个 naive 的想法是缩点后 LCT 维护结果发现不太行。(好像是我不行)

既然想到了用 LCT 维护连通性那么同样可以想到用 DSU 来维护,把所有满足条件的边放入一个 DSU 然后看 $u,v$ 是否能被这些边联通。

有两个关键字欸,我们离线询问排序吧。

把所有边按照 $a$ 排序,把询问按 $b$ 排序。

然后对边的标号分块,这样块内边 $a$ 有序。

然后把每个询问放在满足前面块的 $a$ 都小于等于这个询问的 $a$ 的块里,并且把块内询问 $b$ 排序,然后就可以做了。

代码狼 BH 今天又口胡题解没代码了。

Oops, something went wrong.