给定 -1。
提供一种复杂度正确但常数巨大码量较大的并不优秀的无脑做法,思路来自于模拟赛赛时口糊的,在 Luogu 上可以通过,但赛时在 LemonLime 测的时候大概是因为常数原因被卡的就剩
首先我们不难想到
然后呢最开始我看这道题没太仔细,以为
于是在我发现问题后就尝试优化这个思路,最终的过程大概是这样的:
首先树剖显然,然后线段树上维护区间的不可重复的前 +,实现上用一个 basic_string 存子节点所有值然后排序并各种特判细节做一下即可,不难发现超大的常数就是卡在这里了,这东西某种意义上来讲可以认为其为
然后修改较为简单不再赘述,对于查询直接按照树剖查询并合并,对于不能重复的前 -1。然后我们要再次查询整棵树的结果,在可重复两次的前
当然这里也浅提一下,如果用 multiset 维护
xxxxxxxxxx192123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int >23inline T read(void);24
25struct Edge{26 Edge* nxt;27 int to;28 OPNEW;29}ed[210000];30ROPNEW;31Edge* head[110000];32
33int N, Q;34ll w[110000];35int dep[110000], dfn[110000], hson[110000], siz[110000], ffa[110000], tp[110000], idx[110000];36
37void dfs_pre(int p = 1, int fa = 0){38 dep[p] = dep[fa] + 1;39 siz[p] = 1;40 ffa[p] = fa;41 for(auto i = head[p]; i; i = i->nxt){42 if(SON == fa)continue;43 dfs_pre(SON, p);44 siz[p] += siz[SON];45 if(siz[hson[p]] < siz[SON])hson[p] = SON;46 }47}48void dfs_make(int p = 1, int top = 1){49 tp[p] = top;50 static int cdfn(0);51 dfn[p] = ++cdfn;52 idx[cdfn] = p;53 if(hson[p])dfs_make(hson[p], top);54 for(auto i = head[p]; i; i = i->nxt)55 if(SON != ffa[p] && SON != hson[p])56 dfs_make(SON, SON);57}58
59struct Node{60 ll v[6], vu[6]; //v_max_with_2, v_unique61 Node(void){memset(v, 0, sizeof v), memset(vu, 0, sizeof vu);}62 friend Node operator + (const Node &a, const Node &b){63 Node ret;64 basic_string < ll > values;65 for(int i = 1; i <= 5; ++i){66 if(a.v[i])values += a.v[i];67 if(b.v[i])values += b.v[i];68 }sort(values.begin(), values.end(), greater < ll >());69 for(auto it = values.begin(); it != values.end() && next(it) != values.end() && next(it, 2) != values.end();)70 if(*it == *next(it) && *next(it) == *next(it, 2))it = values.erase(it);71 else advance(it, 1);72 for(int i = 1; i <= 5; ++i)73 ret.v[i] = (int)values.size() >= i ? values.at(i - 1) : 0;74 values.clear();75 for(int i = 1; i <= 5; ++i){76 if(a.vu[i])values += a.vu[i];77 if(b.vu[i])values += b.vu[i];78 }sort(values.begin(), values.end(), greater < ll >());79 values.erase(unique(values.begin(), values.end()), values.end());80 for(int i = 1; i <= 5; ++i)81 ret.vu[i] = (int)values.size() >= i ? values.at(i - 1) : 0;82 return ret;83 }84};85
86class SegTree{87private:88 Node mx[110000 << 2];89 90 91 92public:93 void Pushup(int p){94 mx[p] = mx[LS] + mx[RS];95 }96 void Build(int p = 1, int gl = 1, int gr = N){97 if(gl == gr)return mx[p].v[1] = mx[p].vu[1] = w[idx[gl = gr]], void();98 Build(LS, gl, MID), Build(RS, MID + 1, gr);99 Pushup(p);100 }101 void Modify(int id, int v, int p = 1, int gl = 1, int gr = N){102 if(gl == gr)return mx[p].v[1] += v, mx[p].vu[1] += v, void();103 if(id <= MID)Modify(id, v, LS, gl, MID);104 else Modify(id, v, RS, MID + 1, gr);105 Pushup(p);106 }107 Node Query(int l, int r, int p = 1, int gl = 1, int gr = N){108 // printf("Querying l = %d, r = %d\n", l, r);109 if(l <= gl && gr <= r)return mx[p];110 if(gr < l || r < gl)return Node();111 return Query(l, r, LS, gl, MID) + Query(l, r, RS, MID + 1, gr);112 }113}st;114
115void Make(int s, int t){116 Node cur;117 while(tp[s] != tp[t]){118 if(dep[tp[s]] < dep[tp[t]])swap(s, t);119 cur = cur + st.Query(dfn[tp[s]], dfn[s]);120 s = ffa[tp[s]];121 }if(dep[s] < dep[t])swap(s, t);122 cur = cur + st.Query(dfn[t], dfn[s]);123 if(!cur.vu[1] || !cur.vu[2]){printf("-1\n"); return;}124 Node ret = st.Query(1, N);125 basic_string < ll > tmp;126 for(int i = 1; i <= 5; ++i)if(ret.v[i])tmp += ret.v[i];127 for(int i = 1; i <= 2; ++i)128 if(find(tmp.begin(), tmp.end(), cur.vu[i]) != tmp.end())129 tmp.erase(find(tmp.begin(), tmp.end(), cur.vu[i]));130 if((int)tmp.size() < 2 || ((int)tmp.size() == 2 && tmp.at(0) == tmp.at(1))){printf("%lld 0\n", cur.vu[2]); return;}131 if(tmp.size() == 3 && tmp.at(0) == tmp.at(1)){printf("%lld %lld\n", cur.vu[2], tmp.at(2)); return;}132 printf("%lld %lld\n", cur.vu[2], tmp.at(0) == tmp.at(1) ? tmp.at(2) : tmp.at(1));133 // for(int i = 1; i <= 5; ++i)printf("mxchain mxvu[%d] = %lld\n", i, cur.vu[i]);134 // for(int i = 1; i <= 5; ++i)printf("mxtree mxv[%d] = %lld\n", i, ret.v[i]);135}136
137int main(){138 // freopen("game.in", "r", stdin);139 // freopen("game.out", "w", stdout);140 N = read();141 for(int i = 1; i <= N - 1; ++i){142 int s = read(), t = read();143 head[s] = new Edge{head[s], t};144 head[t] = new Edge{head[t], s};145 }dfs_pre(), dfs_make();146 for(int i = 1; i <= N; ++i)w[i] = read();147 st.Build();148 Q = read();149 while(Q--){150 int opt = read(), x = read(), y = read();151 if(opt == 0)st.Modify(dfn[x], y);152 else Make(x, y);153 }154 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);155 return 0;156}157
158template < typename T >159inline T read(void){160 T ret(0);161 int flag(1);162 char c = getchar();163 while(c != '-' && !isdigit(c))c = getchar();164 if(c == '-')flag = -1, c = getchar();165 while(isdigit(c)){166 ret *= 10;167 ret += int(c - '0');168 c = getchar();169 }170 ret *= flag;171 return ret;172}173
174/*175
17671771 21782 31792 51801 51815 61825 71835 5 3 2 1 5 318461851 3 51861 2 51871 2 11880 2 11891 2 51901 2 1191
192*/update-2023_01_17 初稿