原矩阵
#define ULL unsigned long long
const ULL Base1=2007;
const ULL Base2=2009;
int test,n,m,x,y;
char s[2005][2005],a[2005][2005];
ULL ans,temp[2005][2005],Temp[2005][2005];
ULL Gethash()
{
ULL c,sum=0;
for(int i=0;i<x;i++)
{
c=0;
for(int j=0;j<y;j++)
c=c*Base1+a[i][j];
sum=sum*Base2+c;
}
return sum;
}
void init()
{
ULL t=1,c;
for(int i=0;i<y;i++) t*=Base1;
for(int i=0;i<n;i++)
{
c=0;
for(int j=0;j<y;j++)
c=c*Base1+s[i][j];
temp[i][y-1]=c;
for(int j=y;j<m;j++)
temp[i][j]=temp[i][j-1]*Base1-s[i][j-y]*t+s[i][j];
}
}
int GetAns(ULL Hash)
{
ULL t=1,c;
int ans=0;
for(int i=0;i<x;i++) t*=Base2;
for(int i=y-1;i<m;i++)
{
c=0;
for(int j=0;j<x;j++) c=c*Base2+temp[j][i];
Temp[x-1][i]=c;
if(c==Hash) ans++;
for(int j=x;j<n;j++)
{
Temp[j][i]=Temp[j-1][i]*Base2-temp[j-x][i]*t+temp[j][i];
if(Temp[j][i]==Hash) ans++;
}
}
return ans;
}
int main()
{
scanf("%d%d%d%d",&x,&y,&n,&m);
for(int i=0;i<x;i++)
scanf("%s",a[i]);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
ULL Hash=Gethash();
init();
ans=GetAns(Hash);
printf("%d\n",ans);
return 0;
}
插入
struct Seg{
double k,b;
Seg(){}
Seg(LL X0,LL Y0,LL X1,LL Y1)
{
if(X0==X1) k=0,b=max(Y0,Y1);
else k=1.0*(Y0-Y1)/(X0-X1),b=-k*X0+Y0;
}
double gety(int x){return k*x+b;}
};
const double eps=1e-8;
struct LCST
{
Seg s[4*N];
int m,op,cnt,X0,Y0,X1,Y1;
LL ans,v[4*N];
inline int sig(double x){return fabs(x)<eps?0:(x>0?1:-1);}
void ins(int x,int a,int b,int c,int d,int p)
{
if(c<=a&&b<=d)
{
if(sig(s[p].gety(a)-s[v[x]].gety(a))>0 &&sig(s[p].gety(b)-s[v[x]].gety(b))>0){v[x]=p;return;}
if(sig(s[p].gety(a)-s[v[x]].gety(a))<=0 &&sig(s[p].gety(b)-s[v[x]].gety(b))<=0)return;
if(a==b)return;
}
int mid=(a+b)>>1;
if(c<=mid)ins(x<<1,a,mid,c,d,p);
if(d>mid)ins(x<<1|1,mid+1,b,c,d,p);
}
void ask(int x,int a,int b,int c)
{
if(sig(s[ans].gety(c)-s[v[x]].gety(c))<0)ans=v[x];
else if(!sig(s[ans].gety(c)-s[v[x]].gety(c))&&ans>v[x])ans=v[x];
if(a==b)return;
int mid=(a+b)>>1;
c<=mid?ask(x<<1,a,mid,c):ask(x<<1|1,mid+1,b,c);
}
}tree;
int main()
{
tree.s[0].b=-1;
tree.s[++tree.cnt]=Seg(X0,Y0,X1,Y1);//insert
tree.ins(1,1,N,X0,X1,tree.cnt);
tree.ans=0;
tree.ask(1,1,N,i);
}
change0区间置0,change1区间加1,query询问区间和
struct Data
{
int tag,tag0,sum;
}tree[40100];
void build(int l,int r,int x)
{
tree[x].tag=-1;tree[x].sum=0;tree[x].tag0=0;
if (l==r) return ;
int mid=l+r>>1;
build(l,mid,x<<1);build(mid+1,r,x<<1|1);
}
void Pushdown(int x,int l,int r)
{
if (tree[x].tag==-1) return ;
int mid=l+r>>1;
if (tree[x].tag0==1)
{
tree[x<<1].tag0=1;
tree[x<<1|1].tag0=1;
tree[x<<1].tag=tree[x].tag;
tree[x<<1|1].tag=tree[x].tag;
tree[x<<1].sum=tree[x].tag*(mid-l+1);
tree[x<<1|1].sum=tree[x].tag*(r-mid);
tree[x].tag=-1;tree[x].tag0=0;
}
else
{
if (tree[x<<1].tag==-1) tree[x<<1].tag=tree[x].tag;
else tree[x<<1].tag+=tree[x].tag;
if (tree[x<<1|1].tag==-1) tree[x<<1|1].tag=tree[x].tag;
else tree[x<<1|1].tag+=tree[x].tag;
tree[x<<1].sum+=tree[x].tag*(mid-l+1);
tree[x<<1|1].sum+=tree[x].tag*(r-mid);
tree[x].tag=-1;
}
}
void change0(int lq,int rq,int l,int r,int x)
{
if (lq<=l&&rq>=r)
{
tree[x].tag=0;tree[x].sum=0;tree[x].tag0=1;
return ;
}
Pushdown(x,l,r);
int mid=l+r>>1;
if (lq<=mid) change0(lq,rq,l,mid,x<<1);
if (rq>mid) change0(lq,rq,mid+1,r,x<<1|1);
tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
void change1(int lq,int rq,int l,int r,int x)
{
if (lq<=l&&rq>=r)
{
if (tree[x].tag==-1) tree[x].tag=1;else tree[x].tag++;
tree[x].sum+=r-l+1;
return ;
}
Pushdown(x,l,r);
int mid=l+r>>1;
if (lq<=mid) change1(lq,rq,l,mid,x<<1);
if (rq>mid) change1(lq,rq,mid+1,r,x<<1|1);
tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
int query(int lq,int rq,int l,int r,int x)
{
if (lq<=l&&rq>=r) return tree[x].sum;
Pushdown(x,l,r);
int mid=l+r>>1,ans=0;
if (lq<=mid) ans+=query(lq,rq,l,mid,x<<1);
if (rq>mid) ans+=query(lq,rq,mid+1,r,x<<1|1);
tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
return ans;
}
struct bit
{
int c[maxn],cc[maxn];
void add(int x,int v)
{
for (int i=x;i<=n;i+=i&-i)
c[i]+=v,cc[i]+=x*v;
}
void add(int l,int r,int v){add(l,v);add(r+1,-v);}
int sum(int x)
{
int ret=0;
for (int i=x;i;i-=i&-i)
ret+=(x+1)*c[i]-cc[i];
return ret;
}
int sum(int l,int r){return sum(r)-sum(l-1);}
}
struct bit
{
int c[100010];
inline int lowbit(int x){return x&-x;}
void update(int x,int y,int z,int d){
for (int i=x;i<=n;i+=lowbit(i))
for (int j=y;j<=m;j+=lowbit(j))
for (int k=z;k<=h;k+=lowbit(k))
c[id(i,j,k)]=max(c[id(i,j,k)],d);
}
int query(int x,int y,int z){
int res=-inf;
for (int i=x;i;i-=lowbit(i))
for (int j=y;j;j-=lowbit(j))
for (int k=z;k;k-=lowbit(k))
res=max(res,c[id(i,j,k)]);
return res;
}
}
struct ptree{
int T,n,m,s,k,h[100010],b[100010],d[100010];
struct ST
{
int lc,rc,sum;
}a[2000010];
int Hash(int x)
{
return lower_bound(b+1,b+1+k,x)-b;
}
void build(int l,int r,int x)
{
s++;x=s;
if (l==r) {a[x].lc=a[x].rc=0;return ;}
int mid=(l+r)>>1;
a[x].lc=s+1;build(l,mid,x);
a[x].rc=s+1;build(mid+1,r,x);
}
void change(int x,int y,int z,int xx,int l,int r) //新结点编号,,,对应结点编号,[l,r]
{
if (l==r) {a[x].sum=a[xx].sum+z;return ;}
int mid=(l+r)>>1;
if (y<=mid)
{
a[x].rc=a[xx].rc;
s++;a[x].lc=s;
change(s,y,z,a[xx].lc,l,mid);
}
else
{
a[x].lc=a[xx].lc;
s++;a[x].rc=s;
change(s,y,z,a[xx].rc,mid+1,r);
}
a[x].sum=a[a[x].lc].sum+a[a[x].rc].sum;
}
int query(int x,int y,int z,int l,int r)
{
if (l==r) return b[l];
if (a[a[y].lc].sum-a[a[x].lc].sum>=z) return query(a[x].lc,a[y].lc,z,l,(l+r)>>1);
else return query(a[x].rc,a[y].rc,z-(a[a[y].lc].sum-a[a[x].lc].sum),((l+r)>>1)+1,r);
}
void init(int _n)
{
this->n=_n;
memset(a,0,sizeof(a));
}
void solve()
{
for (int i=1;i<=n;i++)
scanf("%d",&b[i]),d[i]=b[i];
sort(b+1,b+1+n);
k=unique(b+1,b+1+n)-b-1; //离散数据
s=0;
build(1,k,1);
h[0]=1;
for (int i=1;i<=n;i++)
{
s++;h[i]=s;
change(s,Hash(d[i]),1,h[i-1],1,k);
}
}
int query(int x,int y,int z)//区间[x,y]中的第z大数
{
return query(h[x-1],h[y],z,1,n);
}
};
const int maxn=100010;
struct ptree{
int n,m,a[maxn],b[maxn],pos[maxn],cnt;
struct node{int v,nxt;}E[maxn<<1];
int head[maxn],tot;
int fa[maxn],dep[maxn],top[maxn];
int size[maxn],son[maxn];
int lft[maxn<<5],rht[maxn<<5];
int rt[maxn<<5],sum[maxn<<5],sz;
int ans;
void add(int u,int v)
{
E[++tot].nxt=head[u];
E[tot].v=v;
head[u]=tot;
}
void dfs1(int u,int pa)
{
size[u]=1;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(v==pa) continue;
dep[v]=dep[u]+1; fa[v]=u;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int update(int pre,int ll,int rr,int x)
{
int rt=++sz;
lft[rt]=lft[pre]; rht[rt]=rht[pre]; sum[rt]=sum[pre]+1;
if(ll<rr)
{
int mid=ll+rr>>1;
if(x<=mid) lft[rt]=update(lft[pre],ll,mid,x);
else rht[rt]=update(rht[pre],mid+1,rr,x);
}
return rt;
}
void dfs(int u)
{
int x=lower_bound(pos+1,pos+1+cnt,a[u])-pos;
rt[u]=update(rt[fa[u]],1,cnt,x);//以fa[u]为上一棵主席树建树
for(int i=head[u];i;i=E[i].nxt)
if(E[i].v!=fa[u]) dfs(E[i].v);
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];
else v=fa[top[v]];
}
if(dep[u]<dep[v]) return u;
else return v;
}
int query(int u,int v,int lca,int gra,int ll,int rr,int k)
{
if(ll==rr) return ll;
int x=sum[lft[u]]+sum[lft[v]]-sum[lft[lca]]-sum[lft[gra]];//差分得路径
int mid=ll+rr>>1;
if(x>=k) return query(lft[u],lft[v],lft[lca],lft[gra],ll,mid,k);
else return query(rht[u],rht[v],rht[lca],rht[gra],mid+1,rr,k-x);
}
void init(int _n)
{
this->n=_n;
}
int solve()
{
for(int i=1;i<=n;++i)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);
for(int i=1;i<=n;++i)
if(i==1||b[i]!=b[i-1])
pos[++cnt]=b[i];
for(int i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs1(1,0);dfs2(1,1);
dfs(1);
}
int query(int u,int v,int k)//询问(u,v,k),回答u和v这两个节点间第K小的点权
{
int lca=LCA(u,v);
return pos[query(rt[u],rt[v],rt[lca],rt[fa[lca]],1,cnt,k)];
}
}tree;
struct tree_chain_split{
int n,root,point[100010],po,T;
struct data
{
int fa,top,c,ne,d,point,l,r;
LL x;
}a[100010];
vector<int> b[100010];
bool v[100010];
struct ST
{
LL x,tag;
}tree[400010];
void dfs1(int x)
{
v[x]=true;
int Max=0,w=0;
for (int i=0;i<b[x].size();i++)
if (!v[b[x][i]])
{
a[b[x][i]].d=a[x].d+1;
dfs1(b[x][i]);
if (a[b[x][i]].c>Max) Max=a[b[x][i]].c,w=b[x][i];
a[x].c+=a[b[x][i]].c;
a[b[x][i]].fa=x;
}
a[x].ne=w;a[x].c++;
}
void dfs2(int x,int y)
{
v[x]=true,point[++po]=x,a[x].point=po,a[x].top=y;a[x].l=po;
if (!v[a[x].ne] && a[x].ne!=0) dfs2(a[x].ne,a[x].top);
for (int i=0;i<b[x].size();i++)
if (!v[b[x][i]])
dfs2(b[x][i],b[x][i]);
a[x].r=po;
}
void Pushdown(int x,int l,int r)
{
if (tree[x].tag!=0)
{
tree[x<<1].tag+=tree[x].tag;
tree[x<<1|1].tag+=tree[x].tag;
tree[x].x+=tree[x].tag*(LL)(r-l+1);
tree[x].tag=0;
}
}
void change(int lq,int rq,int x,int l,int r,LL z)
{
if (lq<=l && rq>=r) {tree[x].tag+=z;return ;}
int mid=l+r>>1;
Pushdown(x,l,r);
if (lq<=mid) change(lq,rq,x<<1,l,mid,z);
if (rq>mid) change(lq,rq,x<<1|1,mid+1,r,z);
tree[x].x=tree[x<<1].x+tree[x<<1|1].x+tree[x<<1].tag*(LL)(mid-l+1)+tree[x<<1|1].tag*(LL)(r-mid);
}
LL query(int lq,int rq,int x,int l,int r)
{
if (lq<=l && rq>=r) return tree[x].x+tree[x].tag*(LL)(r-l+1);
int mid=l+r>>1;
LL res=0;
Pushdown(x,l,r);
if (lq<=mid) res+=query(lq,rq,x<<1,l,mid);
if (rq>mid) res+=query(lq,rq,x<<1|1,mid+1,r);
tree[x].x=tree[x<<1].x+tree[x<<1|1].x+tree[x<<1].tag*(LL)(mid-l+1)+tree[x<<1|1].tag*(LL)(r-mid);
return res;
}
void build(int l,int r,int x)
{
if (l==r) {tree[x].x=a[point[l]].x;return ;}
int mid=l+r>>1;
build(l,mid,x<<1);build(mid+1,r,x<<1|1);
tree[x].x=tree[x<<1].x+tree[x<<1|1].x;
tree[x].tag=0;
}
void init(int _n,int _r)
{
this->n=_n;this->root=_r;
memset(a,0,sizeof(a));
int x,y;LL z;
for (int i=1;i<=n;i++)
scanf("%lld",&a[i].x);//每一个点的权值
for (int i=1;i<n;i++)
scanf("%d%d",&x,&y),b[x].push_back(y),b[y].push_back(x);
}
void solve()
{
memset(tree,0,sizeof(tree));
memset(v,false,sizeof(v));
a[root].d=1;a[root].fa=1;
dfs1(root);
memset(v,false,sizeof(v));
po=0;
dfs2(root,root);
build(1,n,1);
}
void change_point(int x,LL z){change(a[x].point,a[x].point,1,1,n,z);}
void change_subtree(int x,LL z){change(a[x].l,a[x].r,1,1,n,z);}
void change_chain(int x,int y,LL z)
{
while (a[x].top!=a[y].top)
{
if (a[a[x].top].d<a[a[y].top].d) swap(x,y);
change(a[a[x].top].point,a[x].point,1,1,n,z);
x=a[a[x].top].fa;
}
if (a[x].d>a[y].d) swap(x,y);
change(a[x].point,a[y].point,1,1,n,z);
}
int Find(int x,int y) //找x向上y个
{
while (a[x].d-a[a[x].top].d<y) y-=a[x].d-a[a[x].top].d+1,x=a[a[x].top].fa;
return point[a[x].point-y];
}
int lca(int x,int y) //点x、y的lca
{
while (a[x].top!=a[y].top)
{
if (a[a[x].top].d<a[a[y].top].d) swap(x,y);
x=a[a[x].top].fa;
}
if (a[x].d>a[y].d) swap(x,y);
return x;
}
}tree;
-
1 x y:把a[x]修改为y。
-
2 x y k:查询[x,y]内第k小值。
const int N = 200010, M = 524289;
int n, m, cnt, i, a[N], op[N][4], b[N];
int lower(int x)
{
int l = 1, r = cnt, t, mid;
while (l <= r)
if (b[mid = (l + r) >> 1] <= x)
l = (t = mid) + 1;
else
r = mid - 1;
return t;
}
struct node
{
int val, cnt, sum, p;
node *l, *r;
node()
{
val = sum = cnt = p = 0;
l = r = NULL;
}
inline void up() { sum = l->sum + r->sum + cnt; }
} *blank = new (node), *T[M], pool[2000000], *cur;
void Rotatel(node *&x)
{
node *y = x->r;
x->r = y->l;
x->up();
y->l = x;
y->up();
x = y;
}
void Rotater(node *&x)
{
node *y = x->l;
x->l = y->r;
x->up();
y->r = x;
y->up();
x = y;
}
void Ins(node *&x, int y, int p)
{
if (x == blank)
{
x = cur++;
x-> val = y;
x-> l = x-> r = blank;
x-> sum = x-> cnt = 1;
x-> p = std::rand();
return;
}
x-> sum += p;
if (y == x-> val)
{
x-> cnt += p;
return;
}
if (y<x-> val)
{
Ins(x-> l, y, p);
if (x-> l-> p > x-> p)
Rotater(x);
}
else
{
Ins(x-> r, y, p);
if (x-> r-> p > x-> p)
Rotatel(x);
}
}
int Ask(node *x, int y)
{ //ask how many <= y
int t = 0;
while (x != blank)
if (y<x-> val)
x = x-> l;
else
t += x-> l-> sum + x-> cnt, x = x-> r;
return t;
}
void add(int v, int i, int p)
{
int a = 1, b = cnt, mid, f = 1, x = 1;
while (a < b)
{
if (f)
Ins(T[x], i, p);
mid = (a + b) >> 1;
x <<= 1;
if (f = v <= mid)
b = mid;
else
a = mid + 1, x |= 1;
}
Ins(T[x], i, p);
}
int kth(int l, int r, int k)
{
int x = 1, a = 1, b = cnt, mid;
while (a < b)
{
mid = (a + b) >> 1;
x <<= 1;
int t = Ask(T[x], r)-Ask(T[x], l-1);
if (k <= t)
b = mid;
else
k-= t, a = mid + 1, x |= 1;
}
return a;
}
void build(int x, int a, int b)
{
T[x] = blank;
if (a == b)
return;
int mid = (a + b) >> 1;
build(x << 1, a, mid), build(x << 1 | 1, mid + 1, b);
}
int main()
{
int T;read(T);
blank-> l = blank-> r = blank;
while (T--)
{
read(n);read(m);
cur = pool;
for (i = 1; i <= n; i++)
read(a[i]), b[i] = a[i];
cnt = n;
for (i = 1; i <= m; i++)
{
read(op[i][0]), read(op[i][1]), read(op[i][2]);
if (op[i][0] == 1)
b[++cnt] = op[i][2];
else
read(op[i][3]);
}
sort(b + 1, b + cnt + 1);
for (i = 1; i <= n; i++)
a[i] = lower(a[i]);
for (i = 1; i <= m; i++)
if (op[i][0] == 1)
op[i][2] = lower(op[i][2]);
build(1, 1, cnt);
for (i = 1; i <= n; i++)
add(a[i], i, 1);
for (i = 1; i <= m; i++)
{
if (op[i][0] == 1)
add(a[op[i][1]], op[i][1],-1), add(a[op[i][1]] = op[i][2], op[i][1], 1);
else
printf("%d\n", b[kth(op[i][1], op[i][2], op[i][3])]);
}
}
}
#define MAXN 100010
struct LCA
{
int n,m,S,c[MAXN],h[MAXN],to[MAXN*2],ne[MAXN*2],d[MAXN],p[MAXN*2][20];
void dfs(int u)
{
c[u]=1;
for (int i=h[u];i!=-1;i=ne[i])
{
if (!d[to[i]])
{
d[to[i]]=d[u]+1;
p[to[i]][0]=u;
dfs(to[i]);
c[u]+=c[to[i]];
}
}
}
void solve()
{
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i<=n;i++)
if (p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];
}
int lca(int x,int y)
{
if (d[x]<d[y]) swap(x,y);
int i;
for (i=0;(1<<i)<=d[x];i++);i--;
for (int j=i;j>=0;j--)
if (d[x]-(1<<j)>=d[y]) x=p[x][j];
if (x==y) return x;
for (int j=i;j>=0;j--)
if (p[x][j]!=-1 && p[x][j]!=p[y][j])
x=p[x][j],y=p[y][j];
return p[x][0];
}
void Add(int x,int y)
{
S++;to[S]=x;ne[S]=h[y];h[y]=S;
S++;to[S]=y;ne[S]=h[x];h[x]=S;
}
int Find(int x,int y)
{
y=d[x]-y;
int i;
for (i=0;(1<<i)<=d[x];i++);i--;
for (int j=i;j>=0;j--)
if (d[x]-(1<<j)>=y) x=p[x][j];
return x;
}
void pre(int root)
{
d[root]=1;dfs(root);solve();
}
void init(int _n)
{
memset(h,-1,sizeof(h));
memset(d,0,sizeof(d));
S=0;this->n=_n;this->m=_n-1;
}
}lca;
第一维排序以后不再考虑,第二维利用归并排序,第三维用数据结构维护
- 注意数据结构不要 memset ,手动回撤操作
二位数点问题
int n,m,k,K,b[600010],c[600010];
LL ans;
struct data
{
int x,r,f;
}a[100010];
struct query
{
int l,r,op,le;
query(int a=0,int b=0,int c=0,int d=0):l(a),r(b),op(c),le(d){}
}q[600010],temp[600010];
void add(int x,int y)
{
for (;x<=600000;x+=x&-x) c[x]+=y;
}
int sum(int x)
{
int ans=0;
for (;x;x-=x&-x) ans+=c[x];
return ans;
}
int Hash(int x)
{
return lower_bound(b+1,b+1+K,x)-b;
}
void move(query &x,query y)
{
x.l=y.l;x.r=y.r;x.op=y.op;x.le=y.le;
}
void cdq(int l,int r)
{
if (l==r) return ;
int mid=l+r>>1;
cdq(l,mid);cdq(mid+1,r);
for (int i=l;i<=r;i++)//标记左边的操作
if (i<=mid) q[i].le=1;else q[i].le=0;
int x=l,y=mid+1,s=0;
while(1)//归并排序
{
if (x<=mid&&(y>r||q[x].l<=q[y].l)) move(temp[++s],q[x]),x++;
else if (y<=r) move(temp[++s],q[y]),y++;
else break;
}
s=0;
for (int i=l;i<=r;i++)
{
move(q[i],temp[++s]);
if (temp[s].le==1)//处理左边的操作
{
if (temp[s].op==2) add(Hash(temp[s].r),1);
//printf("+ %d(%d)\n",Hash(temp[s].r),temp[s].r);
}
else//处理右边的询问
{
if (temp[s].op!=2) ans+=(LL)temp[s].op*sum(Hash(temp[s].r));
//printf("ans+=%d*%d\n",temp[s].op,sum(Hash(temp[s].r)));
}
}
s=1;
for (int i=l;i<=r;i++,s++)
if (temp[s].le==1&&temp[s].op==2) add(Hash(temp[s].r),-1);
}
int main()
{
m=0;K=0;
for(int i=1;i<=n;i++)
{
q[++m]=query(a-1,b-1,1);
q[++m]=query(x,y,1);
q[++m]=query(a-1,y,-1);
q[++m]=query(x,b-1,-1);//查询子矩阵 (a,b)-(x,y)
q[++m]=query(x,y,2);//修改位置 (x,y)
b[++K]=x;//离散
}
sort(b+1,b+1+K);
K=unique(b+1,b+1+K)-b-1;
memset(c,0,sizeof(c));
cdq(1,m);
print(ans),puts("");
return 0;
}