题目
思路&&题解
自己的思路:
暴力暴力...
正解:
这道题首先发现贡献是可以拆开的,也就是说对于一个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;
}