n<=10,直接搜索選了那些點便可。ios
複雜度$O(2^n)$,指望得分20分。git
數據是一條鏈。數組
那麼條件轉化爲:選了一個點後,它後面中全部的點的權值比他大。ide
那麼求一遍最長上升子序列便可。優化
複雜度$O(nlogn)$。spa
根據sol2的作法,若是將樹轉化爲dfs序,那麼就和sol3的作法同樣了。code
注意dfs的過程當中,先遍歷右節點,而後左節點。blog
複雜度$O(nlogn)$,指望得分100分。get
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cctype> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -1; for (; isdigit(ch); ch = getchar())x = x * 10 + ch - '0'; return x * f; } const int N = 100005; int w[N], ls[N], rs[N], q[N], f[N], tot; void dfs(int u) { if (!u) return ; q[++tot] = u; dfs(rs[u]); dfs(ls[u]); } int main() { freopen("point.in", "r", stdin); freopen("point.out", "w", stdout); int n = read(); for (int i = 1; i <= n; ++i) w[i] = read(); for (int i = 1; i <= n; ++i) ls[i] = read(), rs[i] = read(); dfs(1); for (int i = 1; i <= n; ++i) q[i] = w[q[i]]; int cnt = 1; f[1] = q[1]; for (int i = 2; i <= n; ++i) { if (q[i] > f[cnt]) f[++cnt] = q[i]; else { int pos = lower_bound(f + 1, f + cnt + 1, q[i]) - f; f[pos] = q[i]; } } cout << cnt; return 0; }
動態開點線段樹直接模擬string
會T,畢竟常數巨大
// 這個代碼寫的有點zz啊 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; #define Rep(i, a, b) for(register int i = a; i <= b; i ++) #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) char buf[(1 << 22)], *p1 = buf, *p2 = buf; #define gc getchar() inline int read() { int x = 0, f = 1; char c = gc; while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc;} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x * f; } #define LL long long const int N = 1e5 + 5; int data[N * 32], Root[N * 32], Lson[N * 32], Rson[N * 32]; int n; int jd; struct Node { int x, y; } ask[N]; int Max; int Poi_A(int l, int r, int &rt, int x) { if(!rt) rt = ++ jd; if(l == r) { if(!data[rt]) { data[rt] = l; return l; } else { return data[rt]; } } int mid = (l + r) >> 1; if(x <= mid) return Poi_A(l, mid, Lson[rt], x); else return Poi_A(mid + 1, r, Rson[rt], x); } void Poi_G(int l, int r, int rt, int x, int num) { if(!rt) return ; if(l == r) { data[rt] = num; return ; } int mid = (l + r) >> 1; if(x <= mid) Poi_G(l, mid, Lson[rt], x, num); else Poi_G(mid + 1, r, Rson[rt], x, num); } struct Node1 { int num, w; } G[N * 3]; int tot; void Dfs(int l, int r, int rt) { if(!rt) return ; if(l == r) { G[++ tot].num = data[rt]; G[tot].w = l; return ; } int mid = (l + r) >> 1; Dfs(l, mid, Lson[rt]); Dfs(mid + 1, r, Rson[rt]); } int Imp; void Sec_A(int l, int r, int rt, int x, int y) { if(!rt) return ; if(x <= l && r <= y) { Imp += data[rt]; return ; } if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, Lson[rt], x, y); if(y > mid) Sec_A(mid + 1, r, Rson[rt], x, y); } void Poi_Mod(int l, int r, int &rt, int x) { if(!rt) rt = ++ jd; data[rt] ++; if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Poi_Mod(l, mid, Lson[rt], x); else Poi_Mod(mid + 1, r, Rson[rt], x); } int tdata[N * 32], tRoot[N * 32], tLson[N * 32], tRson[N * 32]; int tjd; void tSec_A(int l, int r, int rt, int x, int y) { if(!rt) return ; if(x <= l && r <= y) { Imp += tdata[rt]; return ; } if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) tSec_A(l, mid, tLson[rt], x, y); if(y > mid) tSec_A(mid + 1, r, tRson[rt], x, y); } void tPoi_Mod(int l, int r, int &rt, int x) { if(!rt) rt = ++ tjd; tdata[rt] ++; if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) tPoi_Mod(l, mid, tLson[rt], x); else tPoi_Mod(mid + 1, r, tRson[rt], x); } int main() { freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); n = read(); Rep(i, 1, n) { int x = read(), y = read(); if(x > y) swap(x, y); ask[i].x = x, ask[i].y = y; Max = max(Max, ask[i].y); } Rep(i, 1, n) { int x = Poi_A(1, Max, Root[1], ask[i].x); int y = Poi_A(1, Max, Root[1], ask[i].y); Poi_G(1, Max, Root[1], ask[i].x, y); Poi_G(1, Max, Root[1], ask[i].y, x); } Dfs(1, Max, Root[1]); memset(Root, 0, sizeof Root); memset(Lson, 0, sizeof Lson); memset(Rson, 0, sizeof Rson); memset(data, 0, sizeof data); jd = 0; LL Answer = 0; Rep(i, 1, tot) { tPoi_Mod(1, Max, tRoot[1], G[i].w); } Rep(i, 1, tot) { int x = G[i].num, w = G[i].w; Imp = 0; Sec_A(1, Max, Root[1], x + 1, Max); Answer += Imp; int l, r; if(abs(x - w) < 2) { Poi_Mod(1, Max, Root[1], x); continue; } if(x > w) { l = w + 1, r = x - 1; Imp = 0; tSec_A(1, Max, tRoot[1], l, r); Answer += (r - l + 1 - Imp); } else { l = x + 1, r = w - 1; Imp = 0; tSec_A(1, Max, tRoot[1], l, r); Answer += (r - l + 1 - Imp); } Poi_Mod(1, Max, Root[1], x); } cout << Answer; return 0; }
#include<cstdio> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include <iostream> #define LL long long #define lb(x) (x & (-x)) #define Pair pair<int, int> #define fi first #define se second #define MP(x, y) make_pair(x, y) using namespace std; const int MAXN = 1e6 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N; int T[MAXN], date[MAXN], pos[MAXN]; LL sum[MAXN]; // val[i] i位置的元素 // date 離散化數組 Pair P[MAXN]; void add(int x) { for(int i = x; i <= N * 2; i += lb(i)) T[i]++; } LL Query(int x) { LL ans = 0; for(int i = x; i; i -= lb(i)) ans += T[i]; return ans; } int main() { N = read(); for(int i = 1; i <= N; i++) { P[i].fi = read(), P[i].se = read(); date[i] = P[i].fi; date[i + N] = P[i].se; pos[i] = i; pos[i + N] = i + N; } sort(date + 1, date + N * 2 + 1); int num = unique(date + 1, date + N * 2 + 1) - date - 1; for(int i = 1; i <= num; i++) sum[i] = sum[i - 1] + date[i] - date[i - 1] - 1; for(int i = 1; i <= N; i++) { P[i].fi = lower_bound(date + 1, date + num + 1, P[i].fi) - date; P[i].se = lower_bound(date + 1, date + num + 1, P[i].se) - date; swap(pos[P[i].fi], pos[P[i].se]); } LL ans = 0; for(int i = num; i >= 1; i--) { ans += Query(pos[i]); ans += abs(sum[pos[i]] - sum[i]); add(pos[i]); } std:: cout << ans; return 0; }
這道題目考察的是一點思路加上樹上的一些性質。
能夠說是vector加上啓發式合併的一道題目吧。
思路抄襲借鑑於[HNOI2009]夢幻布丁(好吧我只是把它搬到了樹上)
題目意思是在樹上統計同色聯通快個數,更改顏色。
30pts:
咱們發現給定咱們樹上的全部節點的顏色,咱們能夠O(n)求得軍團個數,方法是進行dfs,若是一個結點和他父親節點顏色不一樣,答案就++
而後暴力更改暴力統計答案
30pts2:
咱們能夠優化一下上面那個暴力,用vector紀錄下每種顏色存在的位置,而後枚舉要更改的顏色位置,每一個位置原來對於答案的貢獻是和他相鄰不一樣色的節點個數,咱們減去原來的答案加上更改後的答案就獲得了當前的答案。而後再暴力合併vector就好了。
20pts:是一條鏈,就是夢幻布丁那道題,再也不細說了
100pts: 咱們考慮優化合並操做,咱們發現把x變成y和把y變成x獲得的答案是相同的,因此咱們在合併的時候以及更改顏色的時候都是把顏色少的改爲顏色多的,而且維護每種顏色實際的vector是哪一個,而後就至關於啓發式合併。
每一個點的複雜度是他的度數乘以它被統計答案的次數,最差狀況下每一個點也只會被統計logN次答案,那麼複雜度就是logN * \sum 度數 等於2NlogN
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #include<ctime> #include<cmath> #include<set> #include<map> #define ll long long #define M 200010 using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } int note[M], sz[M], cor[M], id[M]; vector<int>to[M], to1[M]; int n, q, ans; void dfs(int now, int fa) { if(cor[now] != 0 && cor[now] != cor[fa]) ans++; for(int i = 0; i < to[now].size(); i++) { int vj = to[now][i]; if(vj == fa) continue; dfs(vj, now); } } void del(int x) { for(int i = 0; i < to[x].size(); i++) { int vj = to[x][i]; if(cor[vj] != cor[x]) ans--; } } void insert(int x) { for(int i = 0; i < to[x].size(); i++) { int vj = to[x][i]; if(cor[vj] != cor[x]) ans++; } } int tot = 0, tot2 = 0; int main() { n = read(), q = read(); for(int i = 1; i <= n; i++) cor[i] = read(), sz[cor[i]]++, to1[cor[i]].push_back(i), id[i] = i, note[i] = i; for(int i = 1; i < n; i++) { int vi = read(), vj = read(); to[vi].push_back(vj), to[vj].push_back(vi); } to[1].push_back(0), cor[0] = 0x3e3e3e3e; dfs(1, 0); while(q--) { int x = read(), y = read(); int xn = id[x], yn = id[y]; if(sz[xn] < sz[yn]) { tot += sz[xn], tot2 += to1[xn].size(); for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; del(op); to1[yn].push_back(op); } for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; cor[op] = yn; } for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; insert(op); } to1[xn].clear(); sz[yn] += sz[xn]; sz[xn] = 0; id[x] = 0; } else { tot+=sz[yn], tot2 += to1[yn].size(); for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; del(op); to1[xn].push_back(op); } for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; cor[op] = xn; } for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; insert(op); } to1[yn].clear(); sz[xn] += sz[yn]; sz[yn] = 0; id[y] = xn; id[x] = 0; } cout << ans << "\n"; } return 0; }