思考对于第一棵树,当dfs遍历时以u为最深节点,判断它最多能往回走多高(h + 1),那么此时形成的连续链大小为 depth - h。
对于第二棵树,处理好dfs序,一棵树父亲节点的dfs序区间一定包含子树。
对于第一棵树,dfs遍历,当处理到u节点时,先询问它儿子节点的最大值,存入h数组。
然后将它所有的儿子节点,都赋值为depth(u),此时节点的深度,表示这些节点的最近祖先为u。
之后再dfs,维护一条链,dfs到u节点时,维护所有这条链中h的最大值(maxx)。答案为(depth(u) - maxx).
最后取最大值就行了。
上述操作中,维护一个节点所有子节点的值用主席树+标记永久化维护。
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
const int N = 3e5 + 10;
//#define int long long
typedef __int128 lll;
typedef long long ll;
vector<int> g1[N],g2[N];
int n;
// 主席树部分
int rt[N];
#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define d(x) t[x].d
#define lazy(x) t[x].lazy
struct LSegmentTree{
int ls,rs,d;
int lazy;
}t[N << 5];
int LS_idx = 0;
int update(int p,int l,int r,int ql,int qr,int val){
int root = ++LS_idx;
ls(root) = ls(p),rs(root) = rs(p),d(root) = val;
if(ql <= l && qr >= r){
lazy(root) = val;
return root;
}
int mid = (l + r) >> 1;
if(ql <= mid) ls(root) = update(ls(root),l,mid,ql,qr,val);
if(qr > mid) rs(root) = update(rs(root),mid+1,r,ql,qr,val);
return root;
}
int query(int p,int l,int r,int ql,int qr){
int ans = lazy(p);
if(ql <= l && qr >= r) return max(ans,d(p));
int mid = (l + r) >> 1;
if(ql <= mid) ans = max(ans,query(ls(p),l,mid,ql,qr));
if(qr > mid) ans = max(ans,query(rs(p),mid+1,r,ql,qr));
return ans;
}
// dfs序
int L[N],R[N],tim;
void dfs_dfn(int u,int fa){
L[u] = ++tim;
for(auto j : g2[u]){
if(j == fa) continue;
dfs_dfn(j,u);
}
R[u] = tim;
}
// dfs遍历第一棵树
int depth[N],h[N];
void dfs(int u,int fa){
depth[u] = depth[fa] + 1;
h[u] = query(rt[fa],1,n,L[u],R[u]);
rt[u] = update(rt[fa],1,n,L[u],R[u],depth[u]);
for(auto j : g1[u]){
if(j == fa) continue;
dfs(j,u);
}
}
int dfs_ans(int u,int fa,int maxdepth){
int nowmaxdepth = max(maxdepth,h[u]);
int ans = depth[u] - nowmaxdepth;
for(auto j : g1[u]){
if(j == fa) continue;
ans = max(ans,dfs_ans(j,u,nowmaxdepth));
}
return ans;
}
void init(){
for(int i=1;i<=n;i++) g1[i].clear(),g2[i].clear();
for(int i=0;i<=LS_idx;i++) rt[i] = ls(i) = rs(i) = d(i) = lazy(i) = 0;
tim = LS_idx = 0;
}
signed main(){
IOS
int tt; cin>>tt;
while(tt --){
cin>>n;
init();
for(int i=1;i<n;i++){
int a,b; cin>>a>>b;
g1[a].push_back(b);
g1[b].push_back(a);
}
for(int i=1;i<n;i++){
int a,b; cin>>a>>b;
g2[a].push_back(b);
g2[b].push_back(a);
}
dfs_dfn(1,0); dfs(1,0);
cout<<dfs_ans(1,0,0)<<endl;
}
return 0;
}
枚举确定 a i a_i ai 后,枚举 a j , a j a_j,a_j aj,aj的范围是 1 e 6 a i \frac{1e6}{a_i} ai1e6 , 那么总时间复杂度为 ∑ 1 1 e 6 1 e 6 i \sum_{1}^{1e6}\frac{1e6}{i} ∑11e6i1e6 , O ( n l o g n ) O(nlogn) O(nlogn)
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
const int N = 1e6 + 10;
//#define int long long
typedef long long ll;
int cnt[N];
signed main(){
IOS
int n,maxx = 0; cin>>n;
for(int i=1,a;i<=n;i++) cin>>a,cnt[a]++,maxx = max(maxx,a);
ll ans = 0;
for(int i=1;i<=maxx;i++)
for(int j=1;i*j<=maxx;j++)
ans += cnt[i] * cnt[j] * cnt[j*i];
cout<<ans<<endl;
return 0;
}
可以发现,只需要枚举s中所有出现的1的数,和x中出现1的数
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
#define int long long
const int N = 5e3 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int qmi(int a,int b){
int res = 1;
while(b){
if(b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
signed main(){
IOS
int x,s; cin>>x>>s;
map<int,int> mp;
bool plas = true;
for(int i=0;(s >> i);i++){
int j = (s >> i) & 1;
if(j) mp[i] = 1;
}
int cnt = 0;
for(int i=0;(x >> i);i++){
int j = (x >> i) & 1;
if(j){
if(!mp[i]){
plas = false;
}else cnt ++;
}
}
if(!plas) cout<<0<<endl;
else{
int ans = qmi(2,cnt);
if(x == s) ans --;
cout<<ans<<endl;
}
return 0;
}