脑瘫题

9 篇文章 0 订阅
2 篇文章 0 订阅

题目

思路&&题解

自己的思路:

暴力暴力...

正解:

这道题首先发现贡献是可以拆开的,也就是说对于一个c的贡献:

 

显然这里答案是j-i,但是也可以想成是j-m+m-i。这样贡献就拆开了,于是每次只需要和相邻的算一下贡献即可,即用一个结构体存一下左边端点l与右边端点r,如上图就可以存成{l,m},{m,r}

那么对于查询L,R,也就是找到所有满足条件的结构体{l,r},有L<=l , R>=r的权值和

但是现在考虑怎样修改,那么就要多加一维时间,就像带修莫队那样,然后就转化成了三维偏序,于是把贡献与询问放在一起做CDQ即可

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e5 + 3;
int n , m , a[MAXN] , ncnt;
set<int>se[MAXN];
struct node{
    int l , r , tim1 , tim2 , qz , num;
    friend bool operator < ( node a , node b ){
        if( a.r ^ b.r )
		return a.r < b.r;
    	if( a.l ^ b.l )
    		return a.l > b.l;
    	if( a.tim1 ^ b.tim1 ) return a.tim1 < b.tim1;
    	return a.tim2 < b.tim2;
	}
}s[MAXN<<4] , b[MAXN<<4];
inline char GetChar(){
    static char buf[100001],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int &n){
    short f=1;
    long long x=0;
    char c=GetChar();
    while(isdigit(c)==false){
        if(c=='-'){
            f=-1;
		}
        c=GetChar();
    }
    while(isdigit(c)==true){
    	x=(x*10+(c^48));
        c=GetChar();
    }
    n=x*f;
}
int cnt , las[MAXN] , nex[MAXN] , num[MAXN];
ll ans[MAXN] , tre[MAXN];
int s1[MAXN<<4] , p[MAXN<<4];
void modify( int i , int delta ){
    for( ; i <= m + 1; i += ( i & -i) ) tre[i] += delta;
}
ll query( int x ){
    ll sum = 0;
    for( ; x ; x -= ( x & -x ) ) sum += tre[x];
    return sum;
}
void pree( int x ){
    for( ; x <= m + 1 ; x += ( x & -x ) ) tre[x] = 0;
}
void cdq( int l , int r ){
    if( l == r ){ s1[l] = l;return ;}
    int mid = l + r >> 1;
    cdq( l , mid );
    cdq( mid + 1 , r );
    int i = l , j = mid + 1 , o = 0;
    while( i <= mid || j <= r ){
        if( i <= mid && (j > r || b[s1[i]].l >= b[s1[j]].l ) ){
            p[++o] = s1[i];
            if(  b[s1[i]].qz != -1 ){
                modify( b[s1[i]].tim1 , b[s1[i]].qz );
                modify( b[s1[i]].tim2 + 1 , -b[s1[i]].qz );
            }
            i ++;
        }
        else{
            p[++o] = s1[j];
            if( b[s1[j]].qz == -1 )
                ans[b[s1[j]].tim1] += query( b[s1[j]].tim1 );
            j ++;
        }
    }
    for( int i = l ; i <= r ; i ++ ){
        s1[i] = p[i-l+1];
        if( b[s1[i]].qz == -1 ) continue;
        pree( b[p[i-l+1]].tim1 );
        pree( b[p[i-l+1]].tim2 + 1 );
    }
}
vector<int>g;
int main(){
	//	freopen( "ntt.in" , "r" , stdin );
	//freopen( "ntt.out" , "w" , stdout );
    Read( n );Read( m );
    for( register int i = 1 ; i <= n ; i ++ ) Read( a[i] );
    for( register int i = 1 ; i <= n ; i ++ ){
        if( se[a[i]].size() ){
            set<int>::iterator it = se[a[i]].lower_bound( i );
            it --;
            s[++ncnt].l = *it , s[ncnt].r = i , s[ncnt].tim1 = 1 , s[ncnt].qz = i - *it;
            las[i] = *it , nex[*it] = i;
            num[i] = ncnt;
        }
        se[a[i]].insert( i );
    }
    for( int i = 2 ; i <= m + 1; i ++ ){
        int op , x , y;Read( op );Read( x );Read( y );
        if( op == 1 ){
            if( las[x] ){
                if( nex[x] ){
                    int tx = las[x] , ty = nex[x];
                    s[num[ty]].tim2 = i - 1 ;
                    nex[tx] = ty , las[ty] = tx;
                    s[++ncnt].l = tx , s[ncnt].r = ty , s[ncnt].qz = ty - tx , s[ncnt].tim1 = i;num[ty] = ncnt;
				}
                else nex[las[x]] = 0;
                s[num[x]].tim2 = i - 1;
            }
            else if( nex[x] ){
                s[num[nex[x]]].tim2 = i - 1;num[nex[x]] = 0;
                las[nex[x]] = 0;
            }
            las[x] = nex[x] = 0;num[x] = 0;
            se[a[x]].erase( x );
            set<int>::iterator it = se[y].lower_bound( x );
            if( it != se[y].end() ){
                if( num[*it] ){
                    s[num[*it]].tim2 = i - 1;
                }
                if( las[*it] ){
                   int ty = las[*it];
                   num[*it] = ++ncnt;
                   s[ncnt].l = x , s[ncnt].r = *it , s[ncnt].qz = *it - x , s[ncnt].tim1 = i;
                   num[x] = ++ncnt;
                   s[ncnt].l = ty , s[ncnt].r = x, s[ncnt].qz = x - ty , s[ncnt].tim1 = i;
                   nex[ty] = x , nex[x] = *it , las[x] = ty , las[*it] = x;
                }
                else{
                    las[*it] = x;nex[x] = *it;
                    num[*it] = ++ncnt;
                    s[ncnt].l = x , s[ncnt].r = *it , s[ncnt].qz = *it - x , s[ncnt].tim1 = i;
                }
            }
            else if( se[y].size() && it != se[y].begin() ){
                it --;
                nex[*it] = x , las[x] = *it;num[x] = ++ncnt;
                s[ncnt].l = *it , s[ncnt].r = x  , s[ncnt].qz = x - *it , s[ncnt].tim1 = i;
            }
            a[x] = y;
            se[y].insert( x );
        }
        else{
            s[++ncnt].qz = -1 , s[ncnt].l = x , s[ncnt].r = y , s[ncnt].tim1 = s[ncnt].tim2 = i;
            g.push_back( i );
        }
    }
    for( int i = 1 ; i <= ncnt ; i ++ ){
        if( s[i].tim2 == 0 )
            s[i].tim2 = m + 1;
    }
    sort( s + 1 , s + ncnt + 1 );
    int u = 0;
    for( int i = 1 ; i <= ncnt ; i ++ ){
        if( s[i].tim2 < s[i].tim1 ) continue;
        //printf( "%d %d %d %d %d\n" , s[i].l , s[i].r , s[i].qz , s[i].tim1 , s[i].tim2 );
        b[++u] = s[i];
    }
    ncnt = u;
    cdq( 1 , ncnt );
    for( int i = 0 ; i < g.size() ; i ++ ){
        printf( "%lld\n" , ans[g[i]] );
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值