發表文章

[POI] II. Trees

題目連結: http://main.edu.pl/en/archive/oi/2/drz 不難發現其實就照著他說的插入就好,不過因為我寫不太出來該如何判斷往哪邊插跟何時要開點,所以我用另外一種寫法。每次都把最大且相鄰的兩個點合併起來成為一個新節點,而當有人找不到人配時就是不合法的。構造完完整的樹後就直接DFS輸出他要的結果即可。 #include <bits/stdc++.h> using namespace std; #define N 2500 struct lNode{ lNode *l, *r; int next, dep; lNode(){l=NULL;r=NULL;} }; lNode *List[N+5], __nn[4*N]; lNode* nNode(){ static int __cnt=0; return &__nn[__cnt++]; } void dfs2(lNode*); int id=0; void dfs1(lNode*); int main(){ ios_base::sync_with_stdio(0);cin.tie(0); int n;cin>>n; for(int i=0;i<n;i++)List[i]=nNode(); for(int i=0;i<n;i++)List[i]->next=i+1; List[n-1]->next=n-1; int mx=-1; for(int i=0;i<n;i++){ cin>>(List[i]->dep); mx=max(mx, List[i]->dep); } bool flag=1; for(int i=mx;i>=1;i--){ if(!flag)break; ...

[TIOJ] 1163. 6.施工中的道路

題目連結: http://tioj.infor.org/problems/1163 本題看似給定一張無向圖,實在不好求得所有路徑最大值的最小值,但是很明顯可以發現因為是要最小的最大值,所以其實先把最小生成樹找出來後,再在上面求路徑最大值就會是好的,而且如果是寫kruskal演算法,你還可以快速知道兩個點是不是連通的。而要求一棵樹上路徑的最大值,不難發現你可以把路徑拆成a到LCA(a,b)跟b到LCA(a,b) (其中LCA指的是最低共同祖先),然後通常求LCA時會用倍增法,而這時就會發現其實求路徑最大值也可以用倍增法,一樣每次更新這段的最大值,然後找的時候也差不多。 p.s 比較好的講法可以看 這篇 #include <bits/stdc++.h> using namespace std; #define N 30000 #define logN 16 typedef pair<int,int> PII; int djs[N+5]; int Query(int x){if(djs[x]!=x)djs[x]=Query(djs[x]);return djs[x];} inline void Merge(int a,int b){djs[Query(a)]=Query(b);} struct Edge{ int s,e,p; bool operator>(const Edge& x)const{return p>x.p;} }; vector<PII> Tree[N+5]; int time_in[N+5], time_out[N+5],timer=0; PII ff[N+1][logN+1]; void dfs(int,int,int); inline bool anc(int,int); inline int lca(int,int); inline int getMax(int,int); bitset<N+5> walked; int main(){ ios_base::s...

[TIOJ] 1827. Yet another simple task ^____^

題目連結: http://tioj.infor.org/problems/1827 不難發現本題可以對答案二分搜,因為S有單調性,那驗證的時候就是要驗證一個區域是不是有至少k個數小於S,我原本想說用個BIT套treap之類的,但估完複雜度後發現會TLE,實在苦思不知該如何做,直到有人雷了我說誰區間和在用BIT的,我才發現可以用維護前綴和的精神做這題,也就是說每個前綴變成存一棵treap,但是如果每一個前綴都重新插一遍所有東東到treap裡面會發現預處理變成$O(n^2 log(n))$,明顯會TLE,所以不妨用持久化的概念,也就是讓一部分是共用的,有修改到的部分再複製出來就好了,因為複製時最多只會動到一條跟到葉的路徑也就是最多$log(n)$個節點,因此複雜度還是$log(n)$,只是記憶體有點龐大而已。 #include <bits/stdc++.h> using namespace std; #define N 100000 struct treap{ treap *l, *r; int pri,val,size; treap(){l=r=nullptr;size=0;} treap(int x){l=r=nullptr;pri=rand();val=x;size=1;} }; inline int gSize(treap* x){return x?x->size:0;} inline void pull(treap* x){x->size=gSize(x->l)+1+gSize(x->r);} int arr[N+5], n; treap* root[N+5]; bool isOK(int,int,int); void split(treap*,int,treap*&,treap*&); treap* merge(treap*, treap*); int query(treap*,int); int main(){ ios_base::sync_with_stdio(0);cin.tie(0);...

[TIOJ] 1160. 3.動態眾數問題

題目連結: http://tioj.infor.org/problems/1160 其實只要記錄每個數字有多少個,跟紀錄一下當前的眾數是誰以及他的量,當插入一個數字使得他的數量大於原本的眾數時就更新一下眾數資訊,不過不能用array因為他的值域太大,所以不妨考慮用個hash_table(unordered_map) #include <stdio.h> #include <unordered_map> using namespace std; int main(){ unordered_map<int, int> arr; int inp, which=0, size=0; scanf("%d",&inp); while(inp!=0){ if(arr.find(inp) == arr.end()){ arr[inp] = 1; }else{ arr[inp] ++; } if(arr[inp]>size){ which = inp; size = arr[inp]; }else if(arr[inp]==size){ which = (inp<which)?inp:which; } printf("%d %d\n",size, which); scanf("%d",&inp); } return 0; }

[TIOJ] 1609. Problem C 二元搜尋樹 (TRVBST)

題目連結: http://tioj.infor.org/problems/1609 其實一棵二元搜尋樹中序遍歷就是大小關係,所以直接把他給你的數字由小到大sort過一遍後印出來就是答案了 #include <bits/stdc++.h> using namespace std; int arr[1000005]; int main(){ ios_base::sync_with_stdio(0);cin.tie(0); int n;cin>>n; for(int i=0;i<n;i++)cin>>arr[i]; sort(arr,arr+n); for(int i=0;i<n;i++)cout<<arr[i]<<' '; return 0; }

[TIOJ] 1371. 賢狼之網

題目連結: http://tioj.infor.org/problems/1371 裸的凸包,由左至右掃過去維護上凸包跟下凸包,維護方法就是看加入當前這個點是不是在前面兩個所連線的上方(上凸包的話),如果是就把前一個砍掉,不然就塞進去,下凸包也同理。 不過本題要注意相同高度的點就不用輸出了 #include <bits/stdc++.h> using namespace std; typedef long long lld; struct point{ lld x,y; int id; point(){} point(lld a,lld b,lld c){x=a;y=b;id=c;} point(lld a,lld b){x=a;y=b;} }; inline lld cross(const point& a,const point& b){ return a.x*b.y-a.y*b.x; } vector<point> dots; vector<point> cHull; vector<point> ans; int main(){ ios_base::sync_with_stdio(0);cin.tie(0); int n;cin>>n; for(int i=1;i<=n;i++){ lld a,b;cin>>a>>b; dots.push_back(point(a,b,i)); } sort(dots.begin(),dots.end(),[](const point& a,const point& b){return (a.x!=b.x)?(a.x<b.x):(a.y<b.y);}); for(int i=0;i<dots.size();i++){ while(cHul...

[TIOJ] 1178. Convex Hull

題目連結: http://tioj.infor.org/problems/1178 裸裸的凸包題,不過凸包該如何做呢?可以用掃描線的概念,從左至右掃一遍,試試看某個點會不會是凸包的一部分,試驗方法就是看這個點與相鄰且在暫時凸包的兩個點的夾角,如果大於180則中間那個點將不會是凸包的一部分(可用外積判斷是否大於180),這樣可求出上凸包,從右至左再掃一遍就可以找到下凸包了XD #include <bits/stdc++.h> using namespace std; typedef long long lld; struct point{ lld x,y; point(lld a,lld b){x=a;y=b;} }; inline lld cross(point a, point b){ return a.x*b.y-a.y*b.x; } vector<point> dots; int main(){ ios_base::sync_with_stdio(0);cin.tie(0); int n,ans=0;cin>>n; for(int i=0;i<n;i++){ lld a,b;cin>>a>>b; dots.push_back(point(a,b)); } vector<point> cHull; sort(dots.begin(), dots.end(), [](const point& a, const point& b){return a.x<b.x;}); for(auto i:dots){ while(cHull.size()>=2){ int sz=cHull.size()-1; if(cross(point(cHull[sz].x-cHull[sz-1].x,cHull[sz]....