Gym - 102201I Increasing Sequence(DAG找支配树)
给你长度为n(1≤n≤250000)的序列,问对于每个点
i
i
i 存在多少个点
j
j
j (
i
≠
j
i≠j
i=j),
j
j
j 在被删去之后会影响包含
i
i
i 的
L
I
S
LIS
LIS的长度
#include<bits/stdc++.h>
using namespace std;
#define mem(a) memset(a,0,sizeof(a));
const int MAXN = 25e4+10;
const int tier = 17;
vector<int> edge[MAXN];
int tree[MAXN],minn[MAXN],lenmin,ans[MAXN],a[MAXN],n,up[MAXN][18],d[MAXN],dp[MAXN];
inline int lowbit(int x) {return x&-x;}
void insert(int x,int v)
{
dp[x] = v;
while (x <= n)
{
tree[x] = max(tree[x],v);
x += lowbit(x);
}
}
int query(int l,int r)
{
int res = 0;
while (r >= l)
{
if (r - lowbit(r) < l)
{
res = max(res,dp[r]);
r--;
}
else
{
res = max(res,tree[r]);
r -=lowbit(r);
}
}
return res;
}
int LCA(int x,int y)
{
if (d[x] < d[y]) swap(x,y);
int dis = d[x] - d[y];
for (int i = tier;i>=0;i--)
if (dis & (1<<i)) x = up[x][i];
if (x == y) return x;
for (int i = tier;i>=0;i--)
{
if (up[x][i] != up[y][i])
{
x = up[x][i],y = up[y][i];
}
}
return up[x][0];
}
void modify(int x,int fa)
{
d[x] = d[fa]+1;
up[x][0] = fa;
for (int i = 1;i<=17;i++) up[x][i] = up[up[x][i-1]][i-1];
}
inline int read()
{
char c = getchar();
int num = 0;
while (c >='0' && c <= '9')
{
num = num * 10 + c - 48;
c = getchar();
}
return num;
}
inline void write(int x)
{
if(x<0) {
putchar('-');
x = -x;
}
if(x>9) write(x / 10);
putchar(x % 10 + '0');
}
int main()
{
n = read();
for (int i = 1;i<=n;i++) a[i] = read();
for (int i = 1;i<=n;i++)
{
//树状数组实现O(nlog(n))的DP
int j = query(1,a[i]);//j表示LIS最后一位小于a[i]的最长长度是多少
insert(a[i],j+1);//更新树状数组
edge[j+1].push_back(a[i]);//edge存每个长度的最后一位有哪些可能
if (j == 0) d[a[i]] = 1,up[a[i]][0] = 0;//d表示深度,up用来存当前结点的倍增父亲节点是哪个
else
{
//二分查找长度为j的LIS的最后一位<a[i]的最大值
//因为a[i]属于j+1层,说明a[i]比a[j+1]层的每一个都要小
//也就是说edge的每一层都是从大到小排序的
int l = 0,r = edge[j].size()-1;
while (l <= r)
{
int mid = (r + l) / 2;
if (edge[j][mid] < a[i]) r = mid - 1;
else l = mid + 1;
}
//找到<a[i]的最大值edge[j][l],求edge[j][l]和第j层最小值的LCA
//比edge[j][l]小的点的前驱结点肯定也可以是edge[j][l]的前驱结点
//所以找LCA只需要找edge[j][l]和最小点的LCA就可以了
int lca = LCA(edge[j].back(),edge[j][l]);
modify(a[i],lca);
}
}
for (int i = 1;i<=n;i++) ans[i] += d[a[i]] - 1;
mem(up); mem(d); mem(tree); mem(dp);
//倒着再做一遍
for (int i = 1;i<=n;i++) edge[i].clear();
for (int i = n;i>=1;i--)
{
int j = query(a[i],n);
insert(a[i],j+1);
edge[j+1].push_back(a[i]);
if (j == 0) d[a[i]] = 1,up[a[i]][0] = 0;
else
{
int l = lower_bound(edge[j].begin(),edge[j].end(),a[i]) - edge[j].begin();
int lca = LCA(edge[j].back(),edge[j][l]);
modify(a[i],lca);
}
}
for (int i = 1;i<=n;i++) ans[i] += d[a[i]] - 1;
for (int i = 1;i<=n;i++)
{
write(ans[i]);
putchar(' ');
}
}