生活随笔
收集整理的這篇文章主要介紹了
Free tour II SPOJ - FTOUR2 点分治 + 树状数组
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
給你一個有nnn個點的樹,有mmm個點擁堵,連接兩個點的一條邊有一個美麗值,讓你選擇一個路徑,使其經過的擁堵點數不超過kkk且美麗值最大。
n≤2e5,m≤n,k≤mn\le2e5,m\le n,k\le mn≤2e5,m≤n,k≤m
思路:
真惡心啊,這個題還卡時間。
明顯的點分治的題了,在求不超過kkk的擁堵點數且美麗值最大的時候,明顯這是一個前綴最大值,我們用樹狀數組維護一下即可。
在遍歷一顆子樹的時候,需要先更新答案,再將這個子樹的信息更新到trtrtr數組里,注意更新答案的時候需要算上根的擁堵值,更新信息的時候不能算上根的擁堵值。
讓后重置樹狀數組的時候,需要記錄一下更新了那些值,讓后更新即可,不能暴力更新。
還有一個坑就是最后答案需要跟000取maxmaxmax,因為可以美麗值為000。
復雜度O(nlog2n)O(nlog^2n)O(nlog2n)
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
#define lowbit(x) ((x)&(-x))
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=200010,M
=N
*2,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
,k
;
int e
[M
],ne
[M
],h
[N
],w
[M
],idx
;
bool st
[N
];
int dis
[N
],tr
[N
],a
[N
],se
;
vector
<int>v
,used
;void add(int a
,int b
,int c
) {e
[idx
]=b
,w
[idx
]=c
,ne
[idx
]=h
[a
],h
[a
]=idx
++;
}int get_size(int u
,int fa
) {if(st
[u
]) return 0;int sum
=1;for(int i
=h
[u
];~i
;i
=ne
[i
]) {int j
=e
[i
];if(j
==fa
) continue;sum
+=get_size(j
,u
);}return sum
;
} int get_wc(int u
,int fa
,int tot
,int &wc
) {if(st
[u
]) return 0;int sum
=1,mx
=0;for(int i
=h
[u
];~i
;i
=ne
[i
]) {int j
=e
[i
];if(j
==fa
) continue;int now
=get_wc(j
,u
,tot
,wc
);sum
+=now
; mx
=max(mx
,now
);}mx
=max(mx
,tot
-sum
);if(mx
<=tot
/2) wc
=u
;return sum
;
}
void add(int u
,int c
) {for(int i
=u
;i
<=n
+2;i
+=lowbit(i
)) tr
[i
]=max(tr
[i
],c
);
}void sett(int u
,int c
) {for(int i
=u
;i
<=n
+2;i
+=lowbit(i
)) tr
[i
]=c
;
}int get(int u
) {int ans
=-INF
;for(int i
=u
;i
;i
-=lowbit(i
)) ans
=max(ans
,tr
[i
]);return ans
;
}void get_dis(int u
,int fa
,int sum
,int ww
,int &ans
) {if(st
[u
]) return;if(sum
>k
) return;ans
=max(ans
,get(k
-sum
+1)+ww
);for(int i
=h
[u
];~i
;i
=ne
[i
]) {int j
=e
[i
];if(j
==fa
) continue;get_dis(j
,u
,sum
+a
[j
],ww
+w
[i
],ans
);}
}void update(int u
,int fa
,int sum
,int ww
) {if(st
[u
]) return;if(sum
>k
) return;v
.pb(sum
); add(sum
+1,ww
);for(int i
=h
[u
];~i
;i
=ne
[i
]) {int j
=e
[i
];if(j
==fa
) continue;update(j
,u
,sum
+a
[j
],ww
+w
[i
]);}
}int calc(int u
) {if(st
[u
]) return 0;int now
=get_size(u
,-1);int c
=get_wc(u
,-1,get_size(u
,-1),u
);st
[u
]=1;int ans
=0;add(1,0);for(int i
=h
[u
];~i
;i
=ne
[i
]) {int j
=e
[i
];get_dis(j
,u
,a
[j
]+a
[u
],w
[i
],ans
);update(j
,u
,a
[j
],w
[i
]);}for(auto x
:v
) sett(x
+1,-INF
); v
.clear();for(int i
=h
[u
];~i
;i
=ne
[i
]) ans
=max(ans
,calc(e
[i
]));return ans
;
}int main()
{
memset(h
,-1,sizeof(h
));memset(tr
,-0x3f3f3f3f,sizeof(tr
));cin
>>n
>>k
>>m
;for(int i
=1;i
<=m
;i
++) {int x
; scanf("%d",&x
);a
[x
]=1;}for(int i
=1;i
<=n
-1;i
++) {int a
,b
,c
; scanf("%d%d%d",&a
,&b
,&c
);add(a
,b
,c
); add(b
,a
,c
);}printf("%d\n",calc(1));return 0;
}
總結
以上是生活随笔為你收集整理的Free tour II SPOJ - FTOUR2 点分治 + 树状数组的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。