树上逆序对 思维+树状数组

树上逆序对

思维

1,看到逆序对,还是树上和父节点有关系的,就想到树状数组来统计小于等于x的数的个数,只需维护一下该点到根节点的树状数组即可。dfs正好满足。
2,只求一边好求O(n),但是这可能要m次,就不能暴力了,每次处理最多 O(1) 或 O(log(n)) 的复杂度。
3,在线算法不好想,故考虑离线算法,把所有要加入的点先全部加上
4,如果每次询问,不考虑删除以u为根的子树的话,只求此时的逆序对的个数,可以维护一下在此次询问之前的加入的点产生的总贡献即可。
5,对删除u为根的子树来说,只需在dfs到u时,记录一下其子树对该次询问产生的总贡献,然后再用此时总共的逆序对减去子树的贡献即可。
6,注意要离散化
时间复杂的O(nlog(n))


/*

hello world!

Just do it!

start time:2022-05-04 10:23:59.416199

*/

// #pragma GCC optimize (2)
// #pragma G++ optimize (2)
#include <bits/stdc++.h>
#define zero(x) memset(x, 0, sizeof(x));
#define one(x) memset(x, -1, sizeof(x));
#define m_INF(x) memset(x, 0x3f, sizeof(x));
#define m_inf(x) memset(x, 0x3f, sizeof(x));
#define m_f_INF(x) memset(x, -0x3f, sizeof(x));
#define m_f_inf(x) memset(x, -0x3f, sizeof(x));
#define all(x) x.begin(), x.end()
#define endl "\n" 
#define fi first
#define se second
#define lbt(x) ((x)&(-x))
#define pb push_back

struct cmpl{ template <typename A, typename B> bool operator()(const A &a1, const B &b1) { return b1 < a1; } };
struct cmpg{ template <typename A, typename B> bool operator()(const A &a1, const B &b1) { return a1 < b1; } };
#define p_ql(x) priority_queue<x, vector<x>, cmpl>
#define p_qlp(x, y) priority_queue<pair<x, y>, vector<pair<x, y>>, cmpl>
#define p_qg(x) priority_queue<x, vector<x>, cmpg>
#define p_qgp(x, y) priority_queue<pair<x, y>, vector<pair<x, y>>, cmpg>
template<class T> bool ckmin(T& a, const T& b) { return b < a ? a = b, 1 : 0; }
template<class T> bool ckmax(T& a, const T& b) { return a < b ? a = b, 1 : 0; }
#define fo(i,from,to) for(int i=(from),ooo=(from)<(to)?1:-1,oooo=(to)+ooo;i!=oooo;i+=ooo)
#define fol(i,from,to) for(long long i=(from),ooo=(from)<(to)?1:-1,oooo=(to)+ooo;i!=oooo;i+=ooo)
#define foo(i,ooo) for(auto i=ooo.rbegin();i!=ooo.rend();++i)
#define foa(i,from,to) for(int i=(from),ooo=(to);i<=ooo;++i)
#define fos(i,from,to) for(int i=(from),ooo=(to);i>=ooo;--i)

using namespace std;

#ifndef LOCAL
#    define dbg(...) ;
#endif

#define itn int
#define int long long

#ifdef int
#define inf (0x3f3f3f3f3f3f3f3f)
#else
#define inf (0x3f3f3f3f)
#endif

typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii;
const int  dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}}, INF = 0x3f3f3f3f, f_inf = -1044266559, f_INF = -1044266559;
const double eps = 1e-6;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int N = 1e6 + 10;
int n, m;

void init()
{
    
}
int c[N];
void add(int x, int v)
{
	for(; x < N; x += lbt(x)) c[x] += v;
}
int ask(int x)
{
	int res = 0;
	for(; x; x -= lbt(x)) res += c[x];
	return res;
}
int c2[N];
void add2(int x, int v)
{
	for(; x < N; x += lbt(x)) c2[x] += v;
}
int ask2(int x)
{
	int res = 0;
	for(; x; x -= lbt(x)) res += c2[x];
	return res;
}
vector<int> gr[N];
vector<int> task[N];
int a[N], id[N];
int f[N], ans[N];
void dfs(int r, int fa)
{
	for(auto &x : task[r]) {
		ans[x] = ask2(x - 1);
	}
	add2(id[r], ask(N - 1) - ask(a[r]));
	add(a[r], 1);
	for(auto &x : gr[r]) {
		if(r == fa) continue;
		dfs(x, r);
	}
	add(a[r], -1);
	for(auto &x : task[r]) {
		ans[x] -= ask2(x - 1);
	}
}
void solve()
{
    cin >> n >> m;
	foa(i, 1, n) cin >> a[i];
	id[1] = 1;
	foa(i, 2, n) {
		int fa;
		cin >> fa;
		gr[fa].pb(i);
		id[i] = 1;
	}
	int nums = n;
	vector<int> vt;
	foa(i, 1, m) {
		int k;
		cin >> k;
		if(k == 1) {
			int u, x;
			cin >> u >> x;
			++nums;
			a[nums] = x;
			id[nums] = i + 1;
			gr[u].pb(nums);
		} else {
			int k;
			cin >> k;
			task[k].pb(i + 1);
			vt.pb(i + 1);
		}
	}
	vector<int> v1;
	foa(i, 1, nums) v1.pb(a[i]);
	sort(all(v1));
	v1.erase(unique(all(v1)), v1.end());
	foa(i, 1, nums) a[i] = lower_bound(all(v1), a[i]) - v1.begin() + 1;
	dfs(1, 0);
	for(auto &x : vt) {
		int res = ask2(x) + ans[x];
		cout << res << endl;
	}
}
signed main()
{

#ifdef LOCAL
	freopen("read.in", "r", stdin);
	freopen("write.out", "w", stdout);
#endif

	std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0);

	init();

    int t = 0, num2 = 0;

    t = 1;

    if (!t) cin >> t;
    while (t--) {
        //cout<<"Case "<<++num2<<": ";
		solve();
    }
    return 0;

	int num1 = 0;
	//while (scanf("%d", &n) !=-1 && n)
    while (cin >> n && n) {
        //cout<<"Case "<<++num1<<": ";
		solve();
    }
    return 0;

}

posted @   1564269628  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示