洛谷大题单传送门
CF916E Jamie and Tree
有换根操作的树链剖分
三种情况
1:u==rt , return tr [1] . sum;
2:u不是rt的祖先,即u不在1->rt这条路径上,无所谓,直接按u为根的子树返回
3:u是rt的祖先,即u在1->rt这条路径上,最特殊的情况
找到路径u->rt上的u的直系儿子v,
就会发现rt为根时,u子树覆盖不到的地方是v及v的子树
然后返回的就是 [ 1, l [v] - 1] + [ r [v] + 1 , n ]
修改区间操作同上
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef long long ll;
int n,m;
struct node
{
int l,r;
ll sum,tag;
}tr[N<<2];
int hs[N],sz[N],f[N],dep[N],l[N],r[N],tot,id[N],top[N],fa[N];
ll w[N];
vector<int>e[N];
int rt;
void dfs1(int u,int f)
{
fa[u]=f;
hs[u]=-1;
sz[u]=1;
dep[u]=dep[f]+1;
for(auto v: e[u])
{
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[v]>sz[hs[u]])
hs[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
l[u]=++tot;
id[tot]=u;
if(hs[u]!=-1) dfs2(hs[u],t);
for(auto v :e[u] )
if(v!=hs[u]&&v!=fa[u])
dfs2(v,v);
r[u]=tot;
}
void pushup(int u)
{
tr[u].sum=tr[u<<1|1].sum+tr[u<<1].sum;
}
void settag(int u,ll d)
{
tr[u].sum+=1ll*d*(tr[u].r-tr[u].l+1);
tr[u].tag+=d;
}
void pushdown(int u)
{
if(tr[u].tag)
{
settag(u<<1,tr[u].tag);
settag(u<<1|1,tr[u].tag);
tr[u].tag=0;
}
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,r,w[id[l]],0};
return ;
}
else
{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]<dep[v]) return u;
return v;
}
void modify(int u,int l,int r,int ql,int qr,int d)
{
if(l>=ql&&r<=qr)
{
settag(u,d);
return ;
}
int mid=l+r>>1;
pushdown(u);
if(ql<=mid) modify(u<<1,l,mid,ql,qr,d);
if(qr>mid) modify(u<<1|1,mid+1,r,ql,qr,d);
pushup(u);
}
int find(int u)
{
if(u==rt) return -1;
if(l[u]>=l[rt]||r[u]<l[rt]) return 0;
int now=rt;//只要找到他的直系儿子v就行了
while(top[now]!=top[u])
{
if(fa[top[now]]==u) return top[now];
now=fa[top[now]];
}
return hs[u];
}
ll query(int u,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr)
return tr[u].sum;
else
{
int mid=l+r>>1;
pushdown(u);
ll ans=0;
if(ql<=mid) ans+=query(u<<1,l,mid,ql,qr);
if(qr>mid) ans+=query(u<<1|1,mid+1,r,ql,qr);
return ans;
}
}
ll querry_tree(int u)
{
int bo=find(u);
if(bo==-1) return tr[1].sum;
if(bo==0) return query(1,1,n,l[u],r[u]);
else
{
ll ans=query(1,1,n,1,l[bo]-1);
if(r[bo]+1<=n) ans+=query(1,1,n,r[bo]+1,n);
return ans;
}
}
void modify(int u,int d)//分情况讨论
{
int bo=find(u);//找到换根的编号
if(bo==-1) modify(1,1,n,1,n,d);
else if(bo==0) modify(1,1,n,l[u],r[u],d);
else
{
modify(1,1,n,1,l[bo]-1,d);
if(r[bo]+1<=n) modify(1,1,n,r[bo]+1,n,d);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&w[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
rt=1;
for(int i=1;i<=m;i++)
{
int op,x,y,d;
scanf("%d%d",&op,&x);
if(op==1) rt=x;
else if(op==2)
{
scanf("%d%d",&y,&d);
int x1=LCA(x,y);
int y1=LCA(x,rt);
int z1=LCA(y,rt);
if(dep[y1]>dep[x1]) x1=y1;
if(dep[z1]>dep[x1]) x1=z1;
//如果 x,y 都在 r 的子树内,那么LCA 显然为LCA(x,y)。
//如果 x,y 只有一个在 r 的子树内,那么 LCA 肯定为 r。
//如果 x,y 都不在 r 的子树内,我们可以先找到p=LCA(x,r) q=LCA(y,r)。
//如果 p 和 q 不相同,那么我们选择其中较深的一个;如果 p 和 q 相同,那么LCA 就是 p 或 q.
//综上所述,我们可以发现我们要求的LCA 就是LCA(x,y)LCA(x,r),LCA(y,r) 这三者中深度最大
modify(x1,d);
}
else {printf("%lld\n",querry_tree(x));
}
}
return 0;
}
P2590 树的统计
直接树链剖分线段树维护好了
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int l[N],r[N],top[N], id[N],fa[N];
int n,m,hs[N],sz[N],dep[N],tot;
vector<int>e[N];
int a[N];
//线段树维护的是dfs序中的节点元素
struct node
{
int maxn,sum;
}tr[N<<2];
//第一遍dfs 子树大小,重儿子,父亲,深度
void dfs1(int u,int f)
{
sz[u]=1;
dep[u]=dep[f]+1;
hs[u]=-1;
fa[u]=f;
for(auto v :e[u])
{
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[v]>sz[hs[u]])
hs[u]=v;
}
}
//第二遍dfs 每个点的dfs序,重链上的链头元素
void dfs2(int u,int t)
{
top[u]=t;//记录链头元素t
l[u]=++tot;
id[tot]=u;
if(hs[u]!=-1)//如果有重儿子先遍历重儿子,因为是一条链
dfs2(hs[u],t);
for(auto v: e[u])
{
if(v!=fa[u]&&v!=hs[u])
dfs2(v,v);//轻儿子的链头是自己
}
r[u]=tot;
}
void pushup(int u)
{
tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={a[id[l]],a[id[l]]};
return;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int p,int x)
{
if(l==r)
{
//l号点,dfs序中第L个点
tr[u]={x,x};
return;
}
int mid=l+r>>1;
if(p<=mid) update(u<<1,l,mid,p,x);
else update(u<<1|1,mid+1,r,p,x);
pushup(u);
}
//[ql,qr]表示需要查询的区间
int querysum(int u,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr) return tr[u].sum;
else
{
int mid=l+r>>1;
int ans=0;
if(ql<=mid) ans+=querysum(u<<1,l,mid,ql,qr);
if(qr>mid) ans+=querysum(u<<1|1,mid+1,r,ql,qr);
return ans;
}
}
int querymax(int u,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr) return tr[u].maxn;
else
{
int mid=l+r>>1;
int ans=-1e9;
if(ql<=mid) ans=max(ans,querymax(u<<1,l,mid,ql,qr));
if(qr>mid) ans=max(ans,querymax(u<<1|1,mid+1,r,ql,qr));
return ans;
}
}
int qsum(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
ans+=querysum(1,1,n,l[top[u]],l[u]);
u=fa[top[u]];
}else {
ans+=querysum(1,1,n,l[top[v]],l[v]);
v=fa[top[v]];
}
}
if (dep[u]<dep[v])swap(u,v);
ans+=querysum(1,1,n,l[v],l[u]);
return ans;
}
int qmax(int u,int v)
{
int ans=-1e9;
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
ans=max(ans,querymax(1,1,n,l[top[u]],l[u]));//
u=fa[top[u]];
}else {
ans=max(ans,querymax(1,1,n,l[top[v]],l[v]));
v=fa[top[v]];
}
}
if (dep[u]<dep[v])swap(u,v);
ans=max(ans,querymax(1,1,n,l[v],l[u]));
return ans;
}
// 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 v;
// else return u;
// }
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int v,u;
scanf("%d%d",&v,&u);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,y;
char op[10];
scanf("%s%d%d",op,&x,&y);
if (op[1]=='H')update(1,1,n,l[x],y);
if (op[1]=='M')printf("%d\n",qmax(x,y));
if (op[1]=='S')printf("%d\n",qsum(x,y));
}
return 0;
}
P3313 [SDOI2014]旅行
树链剖分+线段树动态开点
一定是动态开点,如果建10^5的线段树内存早就爆了
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long ll;
int fa[N], sz[N], id[N], hs[N], l[N], r[N], top[N];
int n, m, root[N *20], tot;
int val[N], C[N], dep[N];
int rt;
struct node {
int l, r;
int sum, maxn;
} tr[N *20];
vector<int>e[N];
void dfs1(int u, int f) {
dep[u] = dep[f] + 1;
hs[u] = -1;
sz[u] = 1;
fa[u] = f;
for (auto v : e[u]) {
if (v == f)
continue;
dfs1(v, u);
sz[u] += sz[v];
if (hs[u] == -1 || sz[v] > sz[hs[u]])
hs[u] = v;
}
}
void dfs2(int u, int t) {
top[u] = t;
l[u] = ++tot;
id[tot] = u;
if (hs[u] != -1)
dfs2(hs[u], t);
for (auto v : e[u]) {
if (v != fa[u] && v != hs[u])
dfs2(v, v);
}
r[u] = tot;
}
void pushup(int u) {
tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum;
tr[u].maxn = max(tr[tr[u].l].maxn, tr[tr[u].r].maxn);
}
void modify(int &u, int l, int r, int ind, int d) {
if (!u)
u = ++rt;
if (l == r) {
tr[u].maxn = tr[u].sum = d;
return ;
}
int mid = l + r >> 1;
if (ind <= mid)
modify(tr[u].l, l, mid, ind, d);
else
modify(tr[u].r, mid + 1, r, ind, d);
pushup(u);
}
int querys(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr)
return tr[u].sum;
int ans = 0;
int mid = l + r >> 1;
if(ql<=mid) ans+=querys(tr[u].l, l, mid, ql, qr);
if(qr>mid) ans+=querys(tr[u].r, mid + 1, r, ql, qr);
return ans;
}
int query2(int u,int l,int r,int ql,int qr)
{
if (ql <= l && r <= qr)
return tr[u].maxn;
int ans = 0;
int mid = l + r >> 1;
if(ql<=mid) ans=max(ans,querys(tr[u].l, l, mid, ql, qr));
if(qr>mid) ans=max(ans,querys(tr[u].r, mid + 1, r, ql, qr));
return ans;
}
int querysum(int u, int v) {
ll ans = 0;
int xc = C[v];
while (top[v] != top[u]) {
if (dep[top[u]] < dep[top[v]])
swap(u, v);
ans += querys(root[xc], 1, tot, l[top[u]], l[u]);
u = fa[top[u]];
}
if (dep[u] < dep[v])
swap(u, v);
ans += querys(root[xc], 1, tot, l[v], l[u]);
return ans;
}
int querymax(int u, int v) {
int ans = 0;
int xc = C[v];
while (top[v] != top[u]) {
if (dep[top[u]] < dep[top[v]])
swap(u, v);
ans = max(ans, query2(root[xc], 1, tot, l[top[u]], l[u]));
u = fa[top[u]];
}
if (dep[u] < dep[v])
swap(u, v);
ans = max(ans, query2(root[xc], 1, tot, l[v], l[u]));
return ans;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d%d", &val[i], &C[i]);
for (int i = 1; i < n; i++) {
int v, u;
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i <= n; i++)
modify(root[C[i]], 1, tot, l[i], val[i]);
for (int i = 1; i <= m; i++) {
char op[10];
int x, y;
scanf("%s%d%d", op, &x, &y);
if (op[0] == 'C' && op[1] == 'C') {
modify(root[C[x]], 1, tot, l[x], 0);
C[x] = y;
modify(root[C[x]], 1, tot, l[x], val[x]);
}
if (op[0] == 'C' && op[1] == 'W') {
val[x] = y;
modify(root[C[x]], 1, tot, l[x], y);
}
if (op[0] == 'Q' && op[1] == 'S')
printf("%lld\n", querysum(x, y));
if (op[0] == 'Q' && op[1] == 'M')
printf("%lld\n", querymax(x, y));
}
return 0;
}
P3038 [USACO11DEC]Grass Planting G
树链剖分+线段树
板子题,真的很裸
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m;
int fa[N],hs[N],sz[N],id[N],l[N],r[N],tot,p[N];
int a[N];
vector<int>e[N];
int dep[N],dis[N];
int top[N];
struct node
{
int l,r,sum;
int tag;
}tr[N<<2];
void dfs1(int u,int f)
{
fa[u]=f;
dep[u]=dep[f]+1;
hs[u]=-1;
sz[u]=1;
for(auto v : e[u])
{
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[u]>sz[hs[u]])
hs[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
l[u]=++tot;
id[tot]=u;
if(hs[u]!=-1) dfs2(hs[u],t);
for(auto v : e[u])
if(v!=fa[u]&&v!=hs[u])
dfs2(v,v);
r[u]=tot;
}
void pushup(int u)
{
tr[u].sum=tr[u<<1|1].sum+tr[u<<1].sum;
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r)
{
tr[u].sum=0;
return ;
}
else
{
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void settag(int u,int c)
{
tr[u].sum+=c*(tr[u].r-tr[u].l+1);
tr[u].tag+=c;
}
void pushdown(int u )
{
if(tr[u].tag!=0)
{
settag(u<<1,tr[u].tag);
settag(u<<1|1,tr[u].tag);
tr[u].tag=0;
}
}
void modify2(int u,int l,int r,int ql,int qr,int d)
{
if(l>=ql&&r<=qr)
{
settag(u,d);
return ;
}
else
{
pushdown(u);
int mid=l+r>>1;
if(ql <= mid)
modify2(u<<1,l,mid,ql,qr,d);
if(qr > mid)
modify2(u<<1|1,mid+1,r,ql,qr,d);
pushup(u);
}
}
void modify(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify2(1,1,n,l[top[u]],l[u],1);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify2(1,1,n,l[v]+1,l[u],1);
}
int query(int u,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
return tr[u].sum;
}
else
{
pushdown(u);
int mid=l+r>>1;
int ans=0;
if(ql<=mid) ans+=query(u<<1,l,mid,ql,qr);
if(qr>mid) ans+=query(u<<1|1,mid+1,r,ql,qr);
return ans;
}
}
int query(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans+=query(1,1,n,l[top[u]],l[u]);
u=fa[top[u]];
//exit(0);
}
if(dep[u]<dep[v]) swap(u,v);
ans+=query(1,1,n,l[v]+1,l[u]);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int v,u,w;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
char op[2];
int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='P')
{
modify(x,y);
}
else
{
printf("%d\n",query(x,y));
}
}
return 0;
}
P2680 [NOIP2015 提高组] 运输计划
树剖求LCA+二分+树上差分
求最大值中的最小 ,很明显的二分
即二分权值最大的路径的权值最小值,设为mid,只要满足所有路径长度>mid的路径同时减去一条边权后的值<=mid,这个mid就可行,显然,我们减去的这条边必须被所有长度>mid的边都经过,且这条被删去的边要最长。
#include<bits/stdc++.h>
using namespace std;
#define re register
const int N=1000003;
int hs[N],l[N],r[N],fa[N],id[N],p[N];
int dep[N],top[N],tot,a[N],dis[N],sz[N];
vector<pair<int,int>>e[N];
int n,m;
int L,R;
struct node
{
int x,y,lca,len;
}q[N];
int C[N];
void dfs1(int u,int f)
{
sz[u]=1;
dep[u]=dep[f]+1;
hs[u]=-1;
fa[u]=f;
for(auto [v,w] :e[u])
{
if(v==f) continue;
p[v]=w;
dis[v]=dis[u]+w;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[v]>sz[hs[u]])
hs[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
l[u]=++tot;
id[tot]=u;
if(hs[u]!=-1)
dfs2(hs[u],t);
for(auto [v,w]: e[u])
{
if(v!=fa[u]&&v!=hs[u])
dfs2(v,v);
}
r[u]=tot;
}
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 v;
else return u;
}
bool check(int mid)
{
int sum=0;
memset(C,0,sizeof C);
for(int i=1;i<=m;i++)
{
if(q[i].len>mid)
{
C[q[i].x]++,C[q[i].y]++;
C[q[i].lca]-=2;
sum++;
}
}
for(re int i=n;i>=1;i--)
{
C[fa[id[i]]]+=C[id[i]];//每次差分值都累加到父亲节点
if(p[id[i]]>=R-mid&&C[id[i]]==sum)
//存在一条路径满足上述条件则可行
return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int u,w,v;
scanf("%d%d%d",&u,&v,&w);
e[v].push_back({u,w});
e[u].push_back({v,w});
L=max(L,w);
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=m;i++)
{
int v,u;
scanf("%d%d",&v,&u);
int fas=LCA(u,v);
int len=dis[u]+dis[v]-2*dis[fas];
//printf("%d %d %d %d \n",v,u,fas,len);
q[i]={v,u,fas,len};
R=max(R,len);
}
int ql=R-L , qr =R+1;
while(ql<qr)
{
int mid=ql+qr>>1;
if(check(mid)) qr=mid;
else ql=mid+1;
}
printf("%d\n",ql);
return 0;
}
P2146 [NOI2015] 软件包管理器
树链剖分+线段树维护
每次查询时记下上一次的答案,用abs(tr[1].cnt-per)得到答案
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,l[N],r[N],top[N],fa[N],hs[N];
int id[N],sz[N];
int w[N],dep[N],tot;
vector<int>e[N];
struct node
{
int sz;;
int cnt;
int t;
}tr[N<<2];
void dfs1(int u,int f)
{
sz[u]=1;
hs[u]=-1;
fa[u]=f;
dep[u]=dep[f]+1;
for(auto v : e[u])
{
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(hs[u]==-1||sz[v]>sz[hs[u]])
hs[u]=v;
}
}
void dfs2(int u,int t)
{
l[u]=++tot;
id[tot]=u;
top[u]=t;
if(hs[u]!=-1)
dfs2(hs[u],t);
for(auto v : e[u])
{
if(v!=fa[u]&& v != hs[u] )
dfs2(v,v);
}
r[u]=tot;
}
void settag(int u,int t)
{
if(t==1)
{
tr[u].cnt=tr[u].sz;
}
else tr[u].cnt=0;
tr[u].t=t;
}
void update(int u)
{
tr[u].cnt=tr[u<<1].cnt + tr[u<<1|1].cnt;
}
void pushdown(int u)
{
if(tr[u].t!=-1)
{
settag(u<<1,tr[u].t);
settag(u<<1|1,tr[u].t);
tr[u].t=-1;
}
}
void build(int u,int l,int r)
{
tr[u].sz=r-l+1;
tr[u].t=-1;
if(l==r)
{
}else
{
int mid = l+r >> 1;
build(u<<1, l , mid);
build(u<<1|1, mid+1, r);
update(u);
}
}
void modify(int u,int l,int r,int ql,int qr,int c)
{
if(l==ql&&r==qr)
{
settag(u,c);
return ;
}
int mid=l+r >> 1;
pushdown(u);
if(qr<=mid) modify(u<<1,l,mid,ql,qr,c);
else if(ql>mid) modify(u<<1|1,mid+1,r,ql,qr,c);
else
{
modify(u<<1,l,mid,ql,mid,c);
modify(u<<1|1,mid+1,r,mid+1,qr,c);
}
update(u);
}
void install(int x)
{
while(x!=0)
{
modify(1,1,n,l[top[x]],l[x],1);
x=fa[top[x]];
}
}
void uninstall(int x)
{
modify(1,1,n,l[x],r[x],0);
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d",&fa[i]);
fa[i]++;
e[fa[i]].push_back(i);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
int per=0;
while(m--)
{
int a,b,c;
char op[10];
scanf("%s%d",op,&a);
a++;
if(op[0]=='i')
{
install(a);
}
else
{
uninstall(a);
// printf("%d \n",abs(per-tr[1].cnt));
}
printf("%d \n",abs(per-tr[1].cnt));
per=tr[1].cnt;
}
return 0;
}