写几个数据就可以发现把t从小到大排序后是最优的。
那么只要用splay或线段树动态维护一下这个序列就可以了
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 200010
#define X first
#define Y second
using namespace std;
typedef long long ll;
typedef pair<int,int> parii;
int n,m;
ll Ans;
parii A[N],B[N];
struct seg{
int l,r,t; ll x;
}T[N<<2];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
void Build(int g,int l,int r){
T[g].l=l; T[g].r=r;
if(l==r) return ;
int mid=l+r>>1;
Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);
}
void Update(int g,int x,int a,int b){
T[g].x+=a; T[g].t+=b;
if(T[g].l==T[g].r) return ;
int mid=T[g].l+T[g].r>>1;
if(x<=mid) Update(g<<1,x,a,b);
else Update(g<<1|1,x,a,b);
}
ll query1(int g,int l,int r){
if(T[g].l==l&&T[g].r==r) return T[g].x;
int mid=T[g].l+T[g].r>>1;
if(r<=mid) return query1(g<<1,l,r);
else if(l>mid) return query1(g<<1|1,l,r);
else return query1(g<<1,l,mid)+query1(g<<1|1,mid+1,r);
}
int query2(int g,int l,int r){
if(T[g].l==l&&T[g].r==r) return T[g].t;
int mid=T[g].l+T[g].r>>1;
if(r<=mid) return query2(g<<1,l,r);
else if(l>mid) return query2(g<<1|1,l,r);
else return query2(g<<1,l,mid)+query2(g<<1|1,mid+1,r);
}
int main(){
rea(n); rea(m);
for(int i=1;i<=n;i++) rea(A[i].Y),rea(A[i].X),B[i]=A[i];
sort(B+1,B+1+n); ll t=0;
Build(1,1,100001);
for(int i=1;i<=n;i++)
Ans+=B[i].Y-(t+=B[i].X),Update(1,B[i].X,B[i].X,1);
printf("%lld\n",Ans);
for(int i=1;i<=m;i++){
int x; rea(x);
Ans-=A[x].Y-query1(1,1,A[x].X)-1ll*query2(1,A[x].X+1,100001)*A[x].X;
Update(1,A[x].X,-A[x].X,-1);
rea(A[x].Y); rea(A[x].X);
Update(1,A[x].X,A[x].X,1);
Ans+=A[x].Y-query1(1,1,A[x].X)-1ll*query2(1,A[x].X+1,100001)*A[x].X;
printf("%lld\n",Ans);
}
return 0;
}